이번에는 5강을 참고하여 API 호출까지 한다.
RMService에서 request 구성
RMRquest를 받아서 실제 URLRequest를 만드는 메서드다. 현재 rmRequest에서는 request를 구성하기 위한 url과 httpMethod가 정의되어 있다. 이를 이용하여 만들어 리턴하자.
final class RMService {
...
private func request(from rmRequest: RMRequest) -> URLRequest? {
guard let url = rmRequest.url else { return nil }
var request = URLRequest(url: url)
request.httpMethod = rmRequest.httpMethod
return request
}
}
RMRequest에서 execute 메서드 작성
API 통신을 위한 사전준비가 완료됐다. 이제 urlRequest를 가져고 URLSession을 이용해서 데이터 통신을 시작한다. 이번에는 모델을 사용하지 않고 JsonSerialization을 이용하여 정상적으로 데이터가 들어오는지 볼 것이다.
completion 핸들러를 사용해서 데이터를 넘기는 걸 볼 수 있다.
enum RMServiceError: Error {
case failedToCreateRequest
case failedToGetData
}
public func execute<T: Codable>(_ request: RMRequest,
expecting type: T.Type,
completion: @escaping (Result<T, Error>) -> Void) {
guard let urlRequest = self.request(from: request) else {
completion(.failure(RMServiceError.failedToCreateRequest))
return
}
let task = URLSession.shared.dataTask(with: urlRequest) { data, _, error in
guard let data = data, error == nil else {
completion(.failure(error ?? RMServiceError.failedToGetData))
return
}
do {
let json = try JSONSerialization.jsonObject(with: data)
print(String(describing: json))
} catch {
completion(.failure(error))
}
}
task.resume()
}
VC에서 테스트해 보자
테스트를 위해서는 임시로 request를 구성하고 API Call을 진행하면 된다.
이번 코드에는 success에 break를 넣는데 이건 결과물을 확인하기 위함이다.
let request = RMRequest(endpoint: .character,
queryParameters: [
URLQueryItem(name: "name", value: "rick"),
URLQueryItem(name: "status", value: "alive")
])
print(request.url)
RMService.shared.execute(request,
expecting: RMCharacter.self) { result in
switch result {
case .success:
break
case .failure(let error):
print(String(describing: error))
}
}
JSONSerialization -> Model
정상적으로 데이터가 들어온다면 이제 model을 이용하여 데이터를 다룰 것이다.
do {
let result = try JSONDecoder().decode(type.self, from: data)
completion(.success(result))
} catch {
completion(.failure(error))
}
팁
코드를 아름답게 쓰기 위해 인자를 넣는걸 프로퍼티를 선언해서 사용하는 방법이 있다. 예를 들어 RMRequst의 endpointf로 character를 넣어서 사용하려고 한다면 그냥 적지 말고 따로 익스텐션에 프로퍼티를 만들어서 쓰자.
extension RMRequest {
static let listCharactersRequests = RMRequest(endpoint: .character)
}
다시 VC에서 테스트
extension을 적용한 프로퍼티를 이용해서 깔끔하게 코드 작성이 가능해졌다.
- 나는 프로젝트를 진행하면서 여기서 에러가 나서 애먹었는데 원인은 CodingKey에서 설정한 String이 안 맞아서였다. 구체적으로는 gender에서 Male로 들어와야 하는데 male로 적어서... 생각보다 어이없는 실수가 발생할 수 있으니 꼼꼼하게 살펴보자
RMService.shared.execute(.listCharactersRequests, expecting: RMGetAllCharacterResponse.self) { result in
switch result {
case .success(let model):
print(model)
print("Total: "+String(model.info.count))
print("Page result count: "+String(model.results.count))
case .failure(let error):
print(String(describing: error))
}
}
info의 수가 출력된다.
끝
'Swift > Rick & Morty' 카테고리의 다른 글
[iOS] Rick&Morty - #7 CollectionViewCell (0) | 2023.03.04 |
---|---|
[iOS] Rick&Morty - #6 Character List View (0) | 2023.03.03 |
[iOS] Rick&Morty - #4 API Request (0) | 2023.03.01 |
[iOS] Rick&Morty - #3 Data Models (0) | 2023.02.28 |
[iOS] Rick&Morty - #2 Source Control과 API Design (0) | 2023.02.27 |