Search code examples
iosswiftcodablejsondecoder

Handling Alternate API Response Types (typeMismatch)


I have an API where generally, it returns a response like this:

{
    "http_status": 200,
    "error": false,
    "message": "Success.",
    "data": {
         ...
    }
}

However, when there is an error in the request, the response looks like this:

{
    "http_status": 409,
    "error": true,
    "message": "error message here",
    "data": []
}

When I use let decodedResponse = try JSONDecoder().decode(APIResponse.self, from: data) on this struct:

struct APIResponse: Codable {
    var http_status: Int
    var error: Bool
    var message: String
    var data: APIData?
}

and there is a case where an error has happened, I get the response:

Expected to decode Dictionary<String, Any> but found an array instead

Where I want data to be nil in the decoded object.

Any solutions here?

Thanks!


Solution

  • You can customise how a JSON response is decoded by overriding/implementing the init(from decoder: Decoder) throws {

    struct APIResponse: Codable {
        enum CodingKeys: String, CodingKey {
            // I'd rename this to conform to standard Swift conventions
            // but for example...
            case http_status = "http_status"
            case error = "error"
            case message = "message"
            case data = "data"
        }
    
    
        var http_status: Int
        var error: Bool
        var message: String
        var data: APIData?
    
        init(from decoder: Decoder) throws {
            let container = try decoder.container(keyedBy: CodingKeys.self)
    
            http_status = try container.decode(Int.self, forKey: .http_status)
            error = try container.decode(Bool.self, forKey: .error)
            message = try container.decode(String.self, forKey: .message)
    
            guard !error else { return }
    
            data = try container.decode(APIData.self, forKey: .data)
        }
    }