ws-deprecated icon indicating copy to clipboard operation
ws-deprecated copied to clipboard

How to get json returned when server response is 422 ?

Open ntkon opened this issue 6 years ago • 3 comments

Hi, I'm calling a rest api and the server is returning server response 422, but the error I'm getting in the onError block shows 'unknown' with message '-1 - Unknown'

The log shows:

200 'https://myapi.com/'
responseSerializationFailed(Alamofire.AFError.ResponseSerializationFailureReason.jsonSerializationFailed(Error Domain=NSCocoaErrorDomain Code=3840 "Invalid value around character 0." UserInfo={NSDebugDescription=Invalid value around character 0.}))

When I run the api in swagger the json returned is:

{
  "message": "The selected email is invalid.",
  "errors": [
    {
      "name": "email",
      "desc": "The selected email is invalid."
    }
  ]
}

and the headers shown are:

 access-control-allow-credentials: true 
 access-control-allow-headers: X-Platform, Content-Type, X-Auth-Token, Origin, Authorization, X-Requested-With, x-xsrf-token 
 access-control-allow-methods: GET, POST, PUT, DELETE, OPTIONS 
 access-control-allow-origin: http://subbyfinder.naamtechstaging.com 
 cache-control: no-cache, private 
 connection: keep-alive 
 content-type: application/json 
 date: Wed, 20 Jun 2018 05:04:23 GMT 
 server: nginx/1.10.3 (Ubuntu) 
 transfer-encoding: chunked 

Thanks, WS is great and thanks for all your efforts.

ntkon avatar Jun 20 '18 05:06 ntkon

Hi @ntkon Glad you like it ! :)

In case of and error you should be able to get the json via the jsonPayload

import ws

 [...]

myApiCall().onError { e in 
  if let wsError = e as? WSError {
        print(wsError.code)
        print(wsError.status)
        print(wsError.jsonPayload)
    }
}

While we're at it a very common use case is to bridge the default WSError into your own custom Error. For example in our app we have a custom YPError


public func edit(_ user: YPUser) -> AsyncTask {
    return ws.put(restURL(user), params: paramsDicForUser(user)).bridgeError { error in
        if let e = error as? WSError, e.status == .forbidden {
            throw YPError.forbidden
        }
    }
}

This enables you to have only your own domain error inside the app and removes the need to import ws in your ViewControllers :)

Hope this helps,

s4cha avatar Jun 20 '18 08:06 s4cha

Thanks for that @s4cha , I'm still to figure out how to use errors properly, but will get to it (any tips/sample would be welcome).

Sometimes the jsonPayload is not present, specially when there are errors. It seems that if I get anything wrong in the api call, I end up with the cryptic -1-Unknown error. I need to figure out how to handle it when my api call is off, so that I can at least get something useful to track down.

Thanks again for your prompt reply, it's much appreciated.

ntkon avatar Jun 21 '18 06:06 ntkon

Hi @s4cha , I've been doing some debugging and what the server is doing in the above case is returning a html document instead of json. I'm getting the backend guy to explain what is going on... however...

Is there a way that I can just get the returned data (which in this case is not json) and then do my own analysis? Or does alamofire drop this data before ws gets a look in? I tried to use the bridgeError, but it was being called with a WSError, which only 'status' = 'unknown' and 'jsonPayload' = nil

Thanks.

ntkon avatar Jun 26 '18 05:06 ntkon