I am currently working on a project where I am calling a webservice that returns me a JSON that I parse using Codable
, like so :
My Struct:
struct User: Codable {
var name: String
var age: Int
}
API response :
{ "name": "Romiro", "age": 27 }
Decoding code :
let decoded = try! JSONDecoder().decode(User.self, from: data)
We decided to extend the User
infos by adding new fields like so :
struct User: Codable {
var name: String
var age: Int
var detail: Detail
}
struct Detail: Codable {
var id: Int
var dob: Date
}
However the backend is not developed yet, so the API response is still
{ "name": "Romiro", "age": 27 }
Is there a proper way to mock up only the var detail: Detail
part, by loading it from a detail-mock.json
file in project resources that matches the structure of Detail
, but in the mean time keeping the API call for the pre-existing User
part ?
By doing this, I would be able to keep all the logic of calling the endpoint, and shunting the only part that is under development, still by calling
let decoded = try! JSONDecoder().decode(User.self, from: data)
Furthermore, is there a way to do so without altering the json response from the API? I do not want to manually append the detail part to je json response.
Note: Obviously, the User
struct is an example, on my project this is a much more complex struct
You can implement custom decoding on User
, like this:
struct User: Codable {
var name: String
var age: Int
var detail: Detail
enum CodingKeys: CodingKey {
case name, age, detail
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
name = try container.decode(String.self, forKey: .name)
age = try container.decode(Int.self, forKey: .age)
if let detail = try container.decodeIfPresent(Detail.self, forKey: .detail) {
self.detail = detail
} else {
let data = try Data(contentsOf: Bundle.main.url(forResource: "mockupDetail", withExtension: "json")!)
self.detail = try JSONDecoder().decode(Detail.self, from: data)
}
}
}
Notice the if
statement in init
. That is where I decide whether to read the detail
from the actual json, or the mocked json.
This way, you don't need to make detail
optional, but you would need to manually decode the other properties.