HTTP 프로토콜
- HTML : HyperText Markup Languager
- HTTP : HyperText Transfer Protocol
- URL : Uniform Resource Locator
- HyperText 전송에서 시작
-> 이미지, 영상, 파일, JSON, ... 모든 형태의 데이터 전송
- 계층별 프로토콜
- 애플리케이션 : HTTP (데이터를 어떻게 주고 받을지에 대한 약속. request/reply)
- 트랜스포트 : TCP (주고받을 상태 확인 및 검중. port(어떤 앱과 통신하는지)
- 인터넷 : IP (주고 받는 주소, 경로)
- 링크 : 네트워크
- HTTP 요청 메세지
- 시작 라인 (메소드 + 요청대상 + HTTP 버전)
- 헤더 필드 (각종 부가 정보)
- 공백라인
- 메세지 본문 (실제 전송할 데이터. JSON, 이미지, ...)
- HTTP 응답 메세지
- 시작 라인 (HTTP 버전 + 상태코드 + 문구)
- 헤더 필드
- 공백라인
- 메세지 본문 (실제 전송할 데이터. JSON, 이미지, ...)
- 요청 메소드 종류
- GET : 조회 (게시글 읽어오기)
- POST : 등록 (게시글 생성, 댓글 달기)
- PUT : 데이터 대체/생성 (게시글 수정)
- PATCH : (게시글 좋아요)
- DELETE : 삭제 (게시글 삭제)
- 상태 코드 종류
- 2XX (Success)
- 3XX (Redirection)
- 4XX (Client Error)
- 5XX (Serveer Error)
- 데이터 전송 분류
- GET 메소드 : 쿼리 파라미터 통해서 데이터 전송
(ex. 검색어 / 정렬 기준)
- POST / PUT / PATCH 메소드 : 메세지 바디 통해서 데이터 전송
(ex. 회원가입 / 게시글 작성 / 게시글 수정 )
- 응답(Response) 데이터의 형태 : JSON
Rest API
- API 주소 만들 때 알아볼 수 있도록 만든다
iOS에서의 네트워킹
- "서버와 어떻게 통신하는지"
- 요청(Request) - query
- 응답(Response) - data
- 데이터 요청 4단계
- URL 구조체 (URL 만들고)
- URL Session (객체 만들고)
- dataTask
- 시작 (resume)
- 응답 - JSON
-> Class/Struct 형태로 변환
- JSONDecoder()라는 객체
- decode(형태, from: 데이터) 메서드
let movieURL = "http://kobis.or.kr/kobisopenapi/webservice/rest/boxoffice/searchDailyBoxOfficeList.json?&key=본인키주소&targetDt=20210201"
let url = URL(string: movieURL)!
let session = URLSession.shared
let task = session.dataTask(with: url) { (data, response, error) in
if error != nil {
print(error!)
return
}
if let safeData = data {
print(String(decoding: safeData, as: UTF8.self))
}
var movieArray = parseJSON1(safeData)
print(movieArray!)
dump(movieArray!)
}
task.resume()
JSON Parsing
func parseJSON1(_ movieData: Data) -> [DailyBoxOfficeList]? {
do {
let decoder = JSONDecoder()
let decodedData = try decoder.decode(MovieData.self, from: movieData)
return decodedData.boxOfficeResult.dailyBoxOfficeList
} catch {
return nil
}
}
func parseJSON2(_ movieData: Data) -> [DailyBoxOfficeList]? {
do {
var movieLists = [DailyBoxOfficeList]()
if let json = try JSONSerialization.jsonObject(with: movieData) as? [String: Any] {
if let boxOfficeResult = json["boxOfficeResult"] as? [String: Any] {
if let dailyBoxOfficeList = boxOfficeResult["dailyBoxOfficeList"] as? [[String: Any]] {
for item in dailyBoxOfficeList {
let rank = item["rank"] as! String
let movieNm = item["movieNm"] as! String
let audiCnt = item["audiCnt"] as! String
let audiAcc = item["audiAcc"] as! String
let openDt = item["openDt"] as! String
let movie = DailyBoxOfficeList(rank: rank, movieNm: movieNm, audiCnt: audiCnt, audiAcc: audiAcc, openDt: openDt)
movieLists.append(movie)
}
return movieLists
}
}
}
return nil
} catch {
return nil
}
}
struct MovieData: Codable {
let boxOfficeResult: BoxOfficeResult
}
struct BoxOfficeResult: Codable {
let dailyBoxOfficeList: [DailyBoxOfficeList]
}
struct DailyBoxOfficeList: Codable {
let rank: String
let movieNm: String
let audiCnt: String
let audiAcc: String
let openDt: String
}
네트워크 통신의 예시
- 요청(Request) -> 서버데이터(JSON) -> 분석(Parse) -> 변환(Struct/Class)
struct MovieData: Codable {
let boxOfficeResult: BoxOfficeResult
}
struct BoxOfficeResult: Codable {
let dailyBoxOfficeList: [DailyBoxOfficeList]
}
struct DailyBoxOfficeList: Codable {
let rank: String
let movieNm: String
let audiCnt: String
let audiAcc: String
let openDt: String
}
struct Movie {
static var movieId: Int = 0
let movieName: String
let rank: Int
let openDate: String
let todayAudience: Int
let totalAudience: Int
init(movieNm: String, rank: String, openDate: String, audiCnt: String, accAudi: String) {
self.movieName = movieNm
self.rank = Int(rank)!
self.openDate = openDate
self.todayAudience = Int(audiCnt)!
self.totalAudience = Int(accAudi)!
Movie.movieId += 1
}
}
struct MovieDataManager {
let movieURL = "http://kobis.or.kr/kobisopenapi/webservice/rest/boxoffice/searchDailyBoxOfficeList.json?"
let myKey = ""
func fetchMovie(date: String, completion: @escaping ([Movie]?) -> Void) {
let urlString = "\(movieURL)&key=\(myKey)&targetDt=\(date)"
performRequest(with: urlString) { movies in
completion(movies)
}
}
func performRequest(with urlString: String, completion: @escaping ([Movie]?) -> Void) {
print(#function)
guard let url = URL(string: urlString) else { return }
let session = URLSession(configuration: .default)
let task = session.dataTask(with: url) { (data, response, error) in
if error != nil {
print(error!)
completion(nil)
return
}
guard let safeData = data else {
completion(nil)
return
}
if let movies = self.parseJSON(safeData) {
completion(movies)
} else {
completion(nil)
}
}
task.resume()
}
func parseJSON(_ movieData: Data) -> [Movie]? {
print(#function)
let decoder = JSONDecoder()
do {
let decodedData = try decoder.decode(MovieData.self, from: movieData)
let dailyLists = decodedData.boxOfficeResult.dailyBoxOfficeList
let myMovielists = dailyLists.map {
Movie(movieNm: $0.movieNm, rank: $0.rank, openDate: $0.openDt, audiCnt: $0.audiCnt, accAudi: $0.audiAcc)
}
return myMovielists
} catch {
print("파싱 실패")
return nil
}
}
}
var downloadedMovies = [Movie]()
let movieManager = MovieDataManager()
movieManager.fetchMovie(date: "20210201") { (movies) in
if let movies = movies {
downloadedMovies = movies
dump(downloadedMovies)
print("전체 영화 갯수 확인: \(Movie.movieId)")
} else {
print("영화데이터가 없습니다. 또는 다운로드에 실패했습니다.")
}
}