AlamofireObjectMapper: How to handle error responses

Hi,

I use your .responseArray() method to query for json arrays. This works without problems if the query is successful. But if the query fails I get the following response:

{
  "status": "api key invalid"
}

So now my response object (array) is invalid. Is there any way to parse the status message with an different response class, if the first one fails?

Or who should i handle this?

About this issue

  • Original URL
  • State: open
  • Created 8 years ago
  • Reactions: 1
  • Comments: 17 (2 by maintainers)

Most upvoted comments

This is an interesting use case that I have not considered.

If you control the API I would suggest have all requests formed as follows:

{
   "status": true,
   "data": {...}
}

{
   "status": false,
   "error" : "error message goes here"
}

If you don’t control the API, this a bit trickier to handle… perhaps we can include the response string in the returned error?

I’ve just faced the same issue and my solution is to implement a generic class that wraps the object and the error:

class FailableObject<T: Mappable, E: Mappable> : Mappable {
    var object: T?
    var apiError: E?

    required init?(_ map: Map) {}

    func mapping(map: Map) {
        apiError = E(map)
        if apiError != nil {
            apiError!.mapping(map)
        } else {
            object = T(map)
            if object != nil {
                object!.mapping(map)
            }
        }
    }
}

Entities validation and mapping:

class User: Mappable {

    private struct Keys {
        static let userId = "UserId"
        static let tokenString = "TokenString"
        static let expirationDate = "ExpirationDate"
        static let email = "Email"
    }

    required init?(_ map: Map) {
        let requiredKeys = [Keys.userId, Keys.tokenString]

        let keys = Array(map.JSONDictionary.keys)
        var containsAllRequiredKeys = true

        for key in requiredKeys {
            if !keys.contains(key) {
                containsAllRequiredKeys = false
                break
            }
        }

        if !containsAllRequiredKeys {
            return nil
        }
    }

    func mapping(map: Map) { ... }
}

class APIError: Mappable {
    // mapping logic goes here, similar to the 'User' code
}

And after that you can use it like that to fetch the User entity for example:

typealias FailableUser = FailableObject<User, APIError>
Alamofire
    .request(.........)
    .responseObject { (response: Response<FailableUser, NSError>) in 
        if let failableUser = response.result.value {
            if let user = failableUser.object {
                // handle User object
            }
            else if let apiError = failableUser.apiError {
                // handle API error
            }
            else {
                // ...
            }
        }
        else {
            // ...
        }
    }

This code is for the object mapping but I beleive it can be changed for arrays as well. NB: I have written the answer without Xcode so there may be some mistakes, sorry for that 😉 But the idea should be clear I think.

Update: I’ve updated the code and now it should work without errors (checked it in Xcode). Hope that helps.

@AFcgi I use the http header status code. But I would be able to show the user the error message (status hash)