개발/Swift
[Swift] URLSession 통해 async fetch & json 파싱
덤벨로퍼
2022. 10. 4. 09:01
HTTP 메소드, JSON 파싱
http 통신을 위해 URLSession을 사용해보고 얻어온 데이터를 원하는 정보만 디코딩해서 사용하려 한다.
class Network {
func fetchTrends() {
guard let url = URL(string: "<https://api.giphy.com/v1/gifs/search?api_key=\\(apikey)>") else { return }
var request = URLRequest(url: url)
request.httpMethod = "GET"
URLSession.shared.dataTask(with: request) { data, response, error in
if let error = error {
print("Error fetch Trend", error.localizedDescription)
}
print(data)
}
}
}
우선 데이터 fetch를 위한 코드이다. dataTask 클로져 내에 data를 사용할 것이다.
또 URLSession은 async await 을 지원해준다. 따라서 다음과 같이도 사용할수 있다.
static func fetchTrends() async throws {
guard let url = URL(string: "<https://api.giphy.com/v1/gifs/trending?api_key=\\(APIKEY)&offset=\\(offset)>") else {
throw NetworkError.invalidURL }
var request = URLRequest(url: url)
request.httpMethod = "GET"
print("request \\(request)")
let (data, response) = try await URLSession.shared.data(from: url)
}
let (data, response) = try await URLSession.shared.data(from: url) 해당 코드는 비동기로 처리가 된다. 그러므로 아래에 있는 코드는
response를 받을떄까지 기다렸다가 처리된다.
데이터는 아래와 같다. 나는 data-images-original & preview 에 있는
height & width & url 이 필요한 상황이다.

따라서 모델을 다음과 같이 정의했다.
class GifData: Decodable {
var data: [Gif]
}
class Gif : Decodable {
var images: Images?
}
class Images: Decodable {
var original: Image?
var preview: Image?
enum CodingKeys: String, CodingKey {
case original
case preview = "preview_gif"
}
required init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
original = try? values.decode(Image.self, forKey: .original)
preview = try? values.decode(Image.self, forKey: .preview)
}
}
class Image: Decodable {
var url: String?
var height: Int?
var width: Int?
enum CodingKeys: String, CodingKey {
case url, mp4, height, width
}
required init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
url = try? values.decode(String.self, forKey: .url)
width = try? Int(values.decode(String.self, forKey: .width))
height = try? Int(values.decode(String.self, forKey: .height))
}
}
Decodable 한 모델을 통해 받아온 데이터를 모델링 할수 있다.
let decoder = JSONDecoder()
let gif = try decoder.decode(GifData.self, from: data)
return gif.data
전체 코드
static func fetchTrends(offset: Int) async throws -> [Gif] {
guard let url = URL(string: "<https://api.giphy.com/v1/gifs/trending?api_key=\\(APIKEY)&offset=\\(offset)>") else {
throw NetworkError.invalidURL }
var request = URLRequest(url: url)
request.httpMethod = "GET"
let (data, response) = try await URLSession.shared.data(from: url)
guard let response = response as? HTTPURLResponse, response.statusCode == 200 else {
throw NetworkError.invalidServerResponse
}
let decoder = JSONDecoder()
let gif = try decoder.decode(GifData.self, from: data)
return gif.data