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

  2. Simple JSON Continued - Fruits

  3. Nested JSON - Search Results

  4. Utilizing Generics for Mapper Class

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 called name while our Fruit model has a variable called name.

  • The value types are also matching one another. For example, in the fruit.json file, the value type of name is a String while our Fruit Codable model also has a variable name with a String value type.

  • fruit.json is not nested, which means it has a 1-to-1 relationship with our Fruit 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 our Fruit 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 called SearchResults

  • Each individual object from items should be mapped into a model called SearchResult

    • 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:

  1. Create an outer container in which search-result.json only includes the keys data and links.

  2. Using that outer container, decode the key data as an array of the sub-model Data.

  3. Next, decode the key links as an array of the sub-model Link.

  4. Based on the search-result.json file, we know both data and links only contain 1 result in the array. Hence, we’re setting variables to store the only instance of those sub-models.

  5. 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.

Buy Me A Coffee
Previous
Previous

Solving Binary Tree Level Order Traversal

Next
Next

Building a Dad Jokes App 🔨