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.json
has a key calledname
while ourFruit
model has a variable calledname
.The value types are also matching one another. For example, in the
fruit.json
file, the value type ofname
is aString
while ourFruit
Codable model also has a variablename
with aString
value type.fruit.json
is not nested, which means it has a 1-to-1 relationship with ourFruit
model.
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
fruits
The value type of
fruits
is an array of ourFruit
codable 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
items
key into a model calledSearchResults
Each individual object from
items
should be mapped into a model calledSearchResult
For 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.json
only includes the keysdata
andlinks
.Using that outer container, decode the key
data
as an array of the sub-modelData
.Next, decode the key
links
as an array of the sub-modelLink
.Based on the
search-result.json
file, we know bothdata
andlinks
only 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.