Let’s parse the JSON like a Boss with Swift Codable protocol

Shakti Prakash
5 min readOct 4, 2018

--

Over View

In the world of iOS development handling, JSON has always been a tedious process for both new and experienced developers. Many programming tasks involve sending data over a network connection, saving data to disk, or submitting data to APIs and services. These tasks often require data to be encoded and decoded to and from an intermediate format while the data is being transferred.

There are few cool libraries out there like SwiftyJSON which comes handy while parsing JSON.

Swift Codable

The Swift standard library also defines a standardised approach to data encoding and decoding. You adopt this approach by implementing the Encodable and Decodable protocols on your custom types. To support both encoding and decoding, declare conformance to Codable, which combines the Encodable and Decodable protocols. This process is known as making your types codable. Let ‘s dive into this.

Take a look at an example of the first problem. Imagine you have the following JSON:

In the above code snippet our JSON consists of three keys — firstname, lastname, and age. So we created a structure with those keys. Adding Codable to the inheritance list for User triggers automatic conformance that satisfies all of the protocol requirements from Encodable and Decodable.

Oh Its so simple

Scenario-1 (Bad Key naming )

Okay now have look on this example suppose our JSON will be like this :

let json = “””
{
“first_name”: “shakti”,
“last_name”: “prakash”,
“age”:25
}
“””

You’ll notice how the first_name and last_name keys in this JSON don’t make good constant names in Swift. What we want is firstName and lastName.

So how can we define a JSON object in Swift that represents this JSON but with proper Swifty constant names? Don’t worry JSONDecoder has one property called keyDecodingStrategy. By setting this property to .convertFromSnakeCase we can change snake-case keys to camel-case keys.

keyDecodingStrategy

This strategy follows these steps to convert JSON keys to camel-case:

  1. Capitalize each word that follows an underscore.
  2. Remove all underscores that aren’t at the very start or end of the string.
  3. Combine the words into a single string.

The following examples show the result of applying this strategy:

user_id Converts to: userId

base_uri Converts to: baseUri

Here is the code snippet:

import Foundation
import UIKit
let json = “””
{
“first_name”: “shakti”,
“last_name”: “prakash”,
“age”:25
}
“””
let jsonData = Data(json.utf8)struct User:Codable {
var firstName:String
var lastName:String
var age:Int
}
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
do {
let response = try decoder.decode(User.self, from: jsonData)
print(response)
} catch {
print(“Parsing Failed”)
}

CodingKeys

We can also achieve this by using enum called CodingKeys, as explained in the Solution section:

Scenario-2 (Absence of any key or Null Data)

Consider the below case the responding keys in JSON might or might not be present or may be null. You will need to implement the init(from decoder: Decoder) throws function and place your specific logic there.

address key is null here

Suppose you added an address field to your Swift model object:

struct Person: Codable{ 
let firstName: String
let lastName: String
let age: Int
let address: String
private enum CodingKeys: String, CodingKey{
case firstName = “first_name”
case lastName = “last_name”
case age
case address
}
}

If you provided the same JSON as before and tried to decode it into an instance of a Person with the newly added address field, JSONDecoder would throw an error because this field is missing from the JSON and is not defined as optional in the model. To solve this problem, implement the init(from decoder: Decoder) throws function from Decodable and place logic there that fills in the default value for the address field:

So by using decodeIfPresent we can Decodes a value of the given type for the given key, if present. This method returns `nil` if the container does not have a value associated with `key`, or if the value is null.

Scenario -3 (Unpredictable Datatype of the Key )

Codable protocol really helps us a lot while parsing JSON. But the real problem occurs when it comes to handling a key whose data type is unpredictable — it may be a string or maybe Int. Consider the following example:

Our JSON above consists of one Array with two elements. The first element Age is Int type while the second element age is String Type.

If you follow such an approach for decoding, Xcode will throw you an Error. So first, we have to change our datamodel.

Here we defined age as VariacType. Here VariacType is an enum which has two cases one for Int and other one is for String. You can customize as you wish. And the VariacType enum is as follows:

To access the value I have created extension of that:

extension VariacType {
var Value:String {
switch self {
case .int(let intvalue):
return String(intvalue)
case .string(let stringValue):
return stringValue
}
}
}

And here comes the complete Gist File, which you can take a look at. I hope it may help you.

Conclusion

From this article, we learned how to use Swift Codable protocol while creating our JSON model of the response. We also looked at using different kinds of keyDecodingStrategies and deal with dynamic responses (i.e if JSON contains null value or different data type).

Happy Coding!
Shakti Prakash

--

--