Search code examples
swift5decodingcombineopenapi-generator

How do I get Data value from Combine + Alamofire Error response?


Below is my code to call api and it returns Swift.Error when the api call has error.

AccountAPI.postAccount(withSignUpCommand: signUpCommand)
            .sink(receiveCompletion: { [weak self] result in
                guard let self = self else { return }

                switch result {
                    case .finished:
                        self.logger.debug("signUp completed.")
                    case .failure(let error):
                        self.isAuthenticating = false
                        self.logger.error("signUp error : \(error)")
                }
            }, receiveValue: { [weak self] (statusCode, userId) in
                guard let self = self else { return }

                self.logger.debug("signUp status code : \(statusCode)")

                guard (200...299).contains(statusCode) else {
                    return
                }

                self.logger.debug("UserId: \(userId)")
            })
            .store(in: &disposables)

And my publisher here

static func postAccount(
        withSignUpCommand signUpCommand: SignUpCommand,
        apiResponseQueue: DispatchQueue = CloudHospitalClientAPI.apiResponseQueue
    ) -> AnyPublisher<(Int, String), Error> {
        let url = "\(CloudHospitalClientAPI.identityBasePath)/api/v1/accounts"

        let parameters = JSONEncodingHelper.encodingParameters(forEncodableObject: signUpCommand)

        return Future<(Int, String), Error>.init { promise in
            postAccountWithRequestBuilder(withURLString: url, withParameters: parameters, isBody: true).execute(apiResponseQueue) { result -> Void in
                switch result {
                    case let .success(response):
                        promise(.success((response.statusCode, response.body!)))
                    case let .failure(error):
                        promise(.failure(error))
                }
            }
        }
        .eraseToAnyPublisher()

    }

    static func postAccountWithRequestBuilder(
        withURLString URLString: String,
        withParameters parameters: [String: Any]?,
        isBody: Bool
    ) -> RequestBuilder<String> {

        let url = URLComponents(string: URLString)
        let requestBuilder: RequestBuilder<String>.Type = CloudHospitalClientAPI.requestBuilderFactory.getBuilder()

        return requestBuilder.init(method: "POST", URLString: (url?.string ?? URLString), parameters: parameters, isBody: isBody)
    }

When debugging this, I get below result. Debugging

The api error response below format and I'd like to parse this Data but can't access to this value at all. Error response from api(swagger)

Tried to change the Return type to custom error response but had no luck.

Please share some advice where I can insert decoding error response code and return to caller function.

Thanks in advance.

Thanks to Bruno, below is my edited code.

        AccountAPI.postAccount(withSignUpCommand: signUpCommand)
            .sink(receiveCompletion: { [weak self] result in
                guard let self = self else { return }

                switch result {
                    case .finished:
                        self.logger.debug("signUp completed.")
                    case .failure(let error):
                        self.isAuthenticating = false
                        self.logger.error("signUp error : \(error)")
                        if case let ErrorResponse.error(_, data, _) = error {
                            let decoder = JSONDecoder()
                            let identityErrors = try! decoder.decode([IdentityError].self, from: data!)

                            // TODO: Decode `data` here...
                            self.logger.debug("data: \(String(describing: identityErrors))")

                            self.errors = identityErrors
                        }
                }
            }, receiveValue: { [weak self] (statusCode, userId) in
                guard let self = self else { return }

                self.logger.debug("signUp status code : \(statusCode)")

                guard (200...299).contains(statusCode) else {
                    return
                }

                self.logger.debug("UserId: \(userId)")
            })
            .store(in: &disposables)

Solution

  • Can you please check if this solves your problem?

    AccountAPI.postAccount(withSignUpCommand: signUpCommand)
            .sink(receiveCompletion: { [weak self] result in
                guard let self = self else { return }
    
                switch result {
                    case .finished:
                        self.logger.debug("signUp completed.")
                    case .failure(let error):
                        self.isAuthenticating = false
                        self.logger.error("signUp error : \(error)")
    
                        if case let ErrorResponse.error(statusCode, data, error) = error {
    
                            // TODO: Decode `data` here...
                            
                        }
                }
            }, receiveValue: { [weak self] (statusCode, userId) in
                guard let self = self else { return }
    
                self.logger.debug("signUp status code : \(statusCode)")
            })
            .store(in: &disposables)