Master Swift Model Mapping for JSON Data
"Untangling a mess requires patience, perseverance, and a positive attitude. But when you finally succeed, the feeling of accomplishment is priceless."
- Tony Robbins
Marhaba 👋🏼
In today’s post, I’ll be touching on Swift’s Codable to map JSONs to Swift client models. I’ll go through a simple example of mapping a JSON to a client model, then dive into a more complex example using a nested JSON.
Yalla, let’s begin.
Note: I’m assuming that you possess some knowledge of Swift and Xcode, so I won’t dive into fundamentals.
Table of Contents
1. Simple JSON - Fruit
Let’s assume we have the following JSON file stored locally:
How can we map this JSON into a Swift client model? Enter Codable! I’ll begin by creating a struct called Fruit.
Let’s dissect this Fruit model step-by-step:
Fruit’s variables are matching the JSON’s keys word for word. For example,fruit.jsonhas a key callednamewhile ourFruitmodel has a variable calledname.The value types are also matching one another. For example, in the
fruit.jsonfile, the value type ofnameis aStringwhile ourFruitCodable model also has a variablenamewith aStringvalue type.fruit.jsonis not nested, which means it has a 1-to-1 relationship with ourFruitmodel.
Alrighty, enough talk. Let’s see this in action by creating a utility class called Mapper to map the content of fruit.json into our Fruit model.
2. Simple JSON Continued - Fruits
Here’s another JSON file called fruits that expands upon our previous JSON file:
Now how can we map this JSON to our existing Fruit Swift model? To figure it out, let’s highlight what’s different about this fruits.json file:
There’s a new key called
fruitsThe value type of
fruitsis an array of ourFruitcodable model
This is enough info for us to create a new Codable model called Fruits as follows:
Sweet, now I’ll proceed with creating a new function within our Mapper class to map fruits.json into our Fruits model.
3. Nested JSON - Search Results
So far, we used Swift’s Codable to map simple JSONs to client models. Let’s take a look at a more complex JSON below:
To make things even more complicated, let’s say we want to accomplish the following:
Map the array of objects from the
itemskey into a model calledSearchResultsEach individual object from
itemsshould be mapped into a model calledSearchResultFor our model
SearchResult, we only want the following JSON key-pair values:title, nasa_id, date_created, description, and href (links -> href)
Our requirements may sound a bit complicated, so here’s a diagram below to help envision our end goal.
I’ll be taking a top-down approach to building our Codable models. First, I’ll start with creating our SearchResults model.
Next, I’ll create a barebones SearchResult client model.
Next, within the SearchResult model, I’ll create an enum called CodingKeys that will conform to the CodingKey protocol.
Then, I’ll create two sub-models called Data and Link that will contain our desired elements from the data and links keys in our search-result.json file.
Sweet, the outer keys and sub-models are officially set up. Now we can manually set up decoding for our model by utilizing the init(from decoder: Decoder) initializer that’s included.
Here’s a breakdown of the code above:
Create an outer container in which
search-result.jsononly includes the keysdataandlinks.Using that outer container, decode the key
dataas an array of the sub-modelData.Next, decode the key
linksas an array of the sub-modelLink.Based on the
search-result.jsonfile, we know bothdataandlinksonly contain 1 result in the array. Hence, we’re setting variables to store the only instance of those sub-models.Using those sub-models, set up all variables for
SearchResult.
We’re getting close! Our next step is implementing the encode(to:) function that is required whenever we have sub-models. It’s simply the reverse of the initializer we just wrote and converts our properties back into nested containers.
Putting it all together, here are the SearchResults and SearchResult models.
Last but not least, let’s add a function to our Mapper class to map our search-result.json into the SearchResults model.
We successfully mapped a complex nested JSON into a couple of simple Swift models 👏🏼.
4. Utilizing Generics for Mapper Class
Our Mapper utility class has done a great job, but did you notice something? A lot of the mapper functions are applying the same logic. Seems redundant, right? I don’t know about you, but redundancy cramps my programming style. Let’s utilize generics and create an enum to clean up our Mapper class.
Thanks for sticking until the very end. If you’re looking to dive deeper into the code, check out my GitHub repo here. And here are some great resources on Codable:
For any comments and questions on this post, follow up on Twitter.
Make sure to share this article. Appreciate you reading through my blog and until next time.
