3

I am facing a challenge regarding mapping a generic api responses against a model class using codable or object mapper. Suppose I have these api responses against different apis.

{
  "code" : 0, 
  "http_response" : 200,
  "success" : true, 
  "data" : user
}

{
  "code" : 0, 
  "http_response" : 200,
  "success" : true, 
  "data" : locations
}

{
  "code" : 0, 
  "http_response" : 200,
  "success" : true, 
  "data" : countries
}

here user, locations and countries are separate codable/mapper classes.

I will have to construct a class like this

struct APIResponse : Codable {
    let success : Bool?
    let http_response : Int?
    let code : Int?
    let data : ??
}

How I will construct my base class to handle these responses using one class or I will have construct different classes just to change "data" type according to value?

Any kind of help or suggestion will be highly appreciated.

Thanks

1

2 Answers 2

3

Make generic constraint for you struct which says that T has to conform to Decodable and then use this type for specifing type of data

struct APIResponse<T: Decodable>: Decodable {
    var code, httpResponse: Int
    var success: Bool
    var data: T
}

struct User: Decodable {
    var name: String
}

note that I changed name of httpResponse parameter since I'm using keyDecodingStrategy which converts http_response to httpResponse


Then while decoding specify type of T

Single object

let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase

do {
    let responses = try decoder.decode([APIResponse<User>].self, from: data)
    let user = responses[0].data /* data of type `User` of specific response */
} catch { print(error) }

Array of objects

let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase

do {
    let responses = try decoder.decode([APIResponse<[User]>].self, from: data)
    let users = responses[0].data /* data of type `[User]` of specific response */
} catch { print(error) }
Sign up to request clarification or add additional context in comments.

Comments

2

Your decoding method and APIResponse will look like this considering user, countries, locations are decodable,

struct APIResponse<T: Decodable>: Decodable {
    var data: T?
    var code: Int
    var success: Bool
    var http_response: Int
}

func decode<T: Decodable>(data: Data, ofType: T.Type) -> T? {
    do {
        let decoder = JSONDecoder()
        let res = try decoder.decode(APIResponse<T>.self, from: data)
        return res.data
    } catch let parsingError {
        print("Error", parsingError)
    }
    return nil
}

Usage

let data = Data() // From the network api 

//User
let user = decode(data, ofType: User.self)

// Countries
let countries = decode(data, ofType: [Country].self) 

// Locations
let locations = decode(data, ofType: [Location].self) 

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.