Led
Led

Reputation: 517

how to get the error response from MoyaError

similar to this but this time i need to retrieve the JSOn response of the server.

here is my existing code:

return Observable.create{ observer in
            let _ = self.provider
                .request(.getMerchantDetails(qrId: qrId))
                .filterSuccessfulStatusCodes()
                .mapJSON()
                .subscribe(onNext: { response in
                    observer.onNext(RQRMerchant(json: JSON(response)))
                }, onError: { error in
                    observer.onError(error)
                })
            return Disposables.create()

my question is: I can get the error response code 404 by error.localizedDescription But I also want to get the JSON response of the 404 HTTP request.

Upvotes: 1

Views: 2324

Answers (2)

José González
José González

Reputation: 1207

I've been faced with the same problem, and for me the easiest and cleanest solution was to extend MoyaError to include a property for the decoded error object. In my case I'm using Decodable objects, so you could write something like this for a decodable BackendError representing the error you may get from your server:

extension MoyaError {
    public var backendError: BackendError? {
        return response.flatMap {
            try? $0.map(BackendError.self)
        }
    }
}

If you instead prefer to directly deal with JSON you can invoke the mapJSONmethod instead of mapping to a Decodable.

Then you just have to do the following to get the error information for non successful status codes:

onError: { error in
    let backendError = (error as? MoyaError).backendError
}

Upvotes: 1

dsapalo
dsapalo

Reputation: 1847

Since the response of your server is also contained in a JSON, that means that your onNext emissions can be successful JSON responses or invalid JSON responses.

Check the validity of the response using do operator

You can check for the validity of the response by doing the following:

return Observable.create{ observer in

        let _ = self.provider
            .request(.getMerchantDetails(qrId: qrId))
            .filterSuccessfulStatusCodes()
            .mapJSON()
            .do(onNext: { response in 
                 let isValidResponse : Bool = false // check if response is valid

                  if !isValidResponse {
                      throw CustomError.reason
                  }
            })
            .subscribe(onNext: { response in
                observer.onNext(RQRMerchant(json: JSON(response)))

            }, onError: { error in
                observer.onError(error)

            })

        return Disposables.create()
  1. Use the do operator
  2. Check if the onNext emission is indeed a valid emission
  3. Throw an error if it is invalid, signifying that the observable operation has failed.

Response validation

To keep your response validation code in the right place, you can define a class function within your response class definition that verifies if it is valid or not:

class ResponseOfTypeA {
    public class func isValid(response: ResponseOfTypeA) throws {
        if errorConditionIsTrue {
            throw CustomError.reason
        }
    }
}

So that you can do the following:

    // Your observable sequence
    .mapJSON()
    .do(onNext: ResponseOfTypeA.isValid)
    .subscribe(onNext: { response in 
        // the rest of your code

    })

Upvotes: 0

Related Questions