Using Custom Enum to Map JSON in Swift
API consuming application is widely popular today. Most server API provides us, the client, with JSON interface to talk with them. Thanks to Codable
in Swift. We can map JSON object to Swift object without third-party library.
Sometimes, the JSON value is enumeration. Which is, you’ll only need fixed number of values and it’s always best to put them in enumeration. For example, we will use Day
as example.
// The json object
{
"id: 0,
"day": "Sunday"
}
The backend team chooses to use String
rather than Int
to make clear that it is a Day enumeration not Date.
Its trivial to just map the JSON object using this type
struct Booking: Codable {
let id: Int
let day: String
}
And we work with the day using equality or switch.
if booking.day == "Sunday"
else if booking.day ...
Or like this.
struct Booking {
let id: Int
let day: Day
}extension Booking: Codable {
enum CodingKeys: String, CodingKey {
case id, day
} init(from decoder: Decoder) trhows {
// Do map by hand
} func encode(to encoder: Encoder) throws {
// encode by hand
}
}
Nice. But there’s a better solution. We want to make compiler perform typecheck. Or, say, it is strongly typed across the whole apps. And the Day is self-contained. Say, if it also used in another type.
Let’s see.
struct Booking: Codable {
let id: Int
let day: Day
}enum Day: Codable {
case sunday
case monday
...
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
switch try container.decode(String.self) {
case "Sunday": self = .sunday
case ...
default: fatalError()
}
} func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
switch self {
case .sunday: try container.encode("Sunday")
default: fatalError()
}
}
}
The key is to use Encoder.singleValueContainer
method.
As Apple Documentation says
Returns an encoding container appropriate for holding a single primitive value.
Now that you have known this feature, you may start to refactor your code. Happy coding!
Ahh, sure you can improve this code.