티스토리 뷰

문제점

  • 제공받은 API를 사용하다보니, performRequest 메서드는 응답값이 있는 통신만 가능하였고, 응답값 없이 응답코드만 전달해주는 통신에서는 오류가 발생하였다.
  • 임의로 빈 Struct를 만들어서 decodingType에 넣어봐도 실패하였다.

아래의 메서드로는 서버 요청시, response status code만 주고 response값이 없는 요청은 받을 수가 없었습니다.

    static func performRequest<T: Decodable>(route: Router, decodingType: T.Type?) -> Single<T> {

        return Single<T>.create { single in
            do {
                let urlRequest = try route.asURLRequest()

                switch route {
                case .uploadImage(let query):
                    guard let image = query as? ImagePostQuery else { return Disposables.create() }
                    AF.upload(multipartFormData: { multipartFormData in
                        multipartFormData.append(image.file,
                                                 withName: "files",
                                                 fileName: "buyOrNot.jpg",
                                                 mimeType: "image/jpg")
                    }, with: urlRequest)
                    .validate(statusCode: 200..<300)
                    .responseDecodable(of: T.self) { response in
                        switch response.result {
                        case .success(let result):
                            single(.success(result))
                        case .failure(let error):
                            single(.failure(error))
                        }
                    }
                case .editProfile(let query):
                    guard let editData = query as? ProfileQuery else { return Disposables.create() }

                    AF.upload(multipartFormData: { multipartFormData in

                        if let data = editData.file {
                            print("업로드되나요")
                            multipartFormData.append(data, withName: "profile", fileName: "buyOrNot.jpg", mimeType: "image/jpg")
                        }
                        if let nick = editData.nick.data(using: .utf8) {
                            multipartFormData.append(nick, withName: "nick")
                        }
                    }, with: urlRequest)
                    .validate(statusCode: 200..<300)
                    .responseDecodable(of: T.self) { response in
                        switch response.result {
                        case .success(let result):
                            print("하ㅓ잉")
                            single(.success(result))
                        case .failure(let error):
                            print(error)
                            single(.failure(error))
                        }
                    }
                default:
                    AF.request(urlRequest)
                        .validate(statusCode: 200..<300)
                        .responseDecodable(of: T.self) { response in
                            print(response.request?.url)

                            switch response.result {
                            case .success(let result):
                                print("success")
                                single(.success(result))
                                print(response.response?.statusCode)
                            case .failure(let error):
                                print("fail")
                                print(response.response?.statusCode)
                                single(.failure(error))

                            }
                        }
                }
            } catch {
                single(.failure(error))
            }

            return Disposables.create()
        }
        .retry(when: { errors in
            errors.flatMap { error -> Single<Void> in
                guard let afError = error as? AFError, afError.responseCode == 419 else {
                    throw error
                }
                return refreshToken().flatMap { _ in
                    performRequest(route: route, decodingType: T.self).map { _ in
                        Void()
                    }
                }
            }
        })
    }

해결방법

  • performRequest 메서드에 통합을 하고 싶었지만, 해당 메서드는 제네릭을 활용하였기 때문에 decodingType에 nil을 넣는 방법으로 구현을 하면 T의 타입을 유추할수 없기 때문에 Generic parameter 'T' could not be inferred 와 같은 컴파일 오류가 발생합니다.
  • 더 좋은 방법이 있을 것 같지만...
  • 우선은.. 아래와 같이 VoidType에 사용할 메서드를 추가 생성하고 Alamofire의 responseDecodable 이 아닌, response로 동작할 수 있도록 구현하였습니다.
//응답값 없을때
    static func performRequestVoidType(route: Router) -> Single<Void> {
        return Single<Void>.create { single in
            do {
                let urlRequest = try route.asURLRequest()

                AF.request(urlRequest)
                    .validate(statusCode: 200..<300)
                    .response { response in
                        switch response.result {
                        case .success:
                            print("Request succeeded with status code: \(String(describing: response.response?.statusCode))")
                            single(.success(()))
                        case .failure(let error):
                            print("Request failed with error: \(error.localizedDescription) and status code: \(String(describing: response.response?.statusCode))")
                            single(.failure(error))
                        }
                    }
            } catch {
                single(.failure(error))
            }

            return Disposables.create()
        }
        .retry(when: { errors in
            errors.flatMap { error -> Single<Void> in
                guard let afError = error as? AFError, afError.responseCode == 419 else {
                    throw error
                }
                return refreshToken().flatMap { _ in
                    performRequestVoidType(route: route).map { Void() }
                }
            }
        })
    }
  • 완벽하지는 않지만, Router Pattern을 이용하여, 약 33개의 API 통신을 위 2개의 메서드로 구현하였으니 우선은 만족..!
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/07   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
글 보관함