Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle failure cases of JSON response using Codable?

I have some JSON response, that I take from a server. In success case, it might be like:

{
  "success": true, 
  "data": [
    {
       /// something here 
    }
  ]
}

If all server responses would be successful, it would be really easy to parse that JSON. But we have also failure cases like:

{
  "success": false, 
  "msg": "Your session expired",
  "end_session": true 
}

That means we need to handle two cases. As you noticed, attributes like success, msg may occur in any response. In order to handle that, I created following struct:

struct RegularResponse<T: Codable>: Codable {
let success: Bool
let msg: String?
let endSession: Bool?
let data: T?

enum CodingKeys: String, CodingKey {
    case success, msg, data
    case endSession = "end_session"
}

}

It may contain some data if response is successfull or otherwise, it is possible to identify why the error occurred(using success attribute or msg). Parsing process would go like following:

let model = try JSONDecoder().decode(RegularResponse<MyModel>.self, from: data)

            if model.success {
                // do something with data 
            } else {
               // handle error 
            }

Everything works fine, but what if following JSON comes as following:

{
  "success": true, 
  "name": "Jon Snow", 
  "living_place": "Nights Watch",
  //some other fields
}

Here, I don't have data attribute. It means, my RegularResponse cannot be parsed. So, the question is how to handle these kind of situations? My idea for solution is simple: always put data in success cases into data field on my API. By doing so, my RegularResponse will always work, no matter what is inside data. But, it requires changes on a server side. Can this be fixed in a client side, not changing a server side? In other words, how to handle above situation in Swift using Codable?

like image 521
neo Avatar asked Nov 14 '19 09:11

neo


1 Answers

I'm not sure if this is the best solution but if you know that your error response is in that shape, i.e.:

{
  "success": false, 
  "msg": "Some error", 
  "end_session": "true",
}

then you could make another Codable struct/class that follows this response.

struct ErrorResponse: Codable {
    let success: Bool
    let msg: String
    let end_session: String
}

and then when you are responding to your JSON you could adjust your code to:

if let successResponse = try? JSONDecoder().decode(RegularResponse<MyModel>.self, from: data) {
    //handle success
} else if let responseError = try? JSONDecoder().decode(ErrorResponse.self, from data) {
    //handle your error
}
like image 97
Alan S Avatar answered Nov 01 '22 05:11

Alan S