Consuming JSON Using Plain Vanilla Swift
When designing a Web API, the transfer medium is as important as the structure of the API. You can use XML, JSON or if you are wearing your big boy pants, SOAP. JSON is mostly preferred because it provides a small footprint and it can be mapped easily to your model classes. In this post we are going to look at different ways of consuming the JSON response without using any JSON parsing library.
Let’s start with something simple and cute! What is simple and cute?
I love Pokemon so much that I created a server side Swift API in Vapor, which returns an array of Pokemons. You can check out the API using this link.
Plan Vanilla Dictionaries:
In this first approach we are going to consume JSON in the form of array of dictionaries. We use the JSONSerialization class to convert the returned data into an appropriate data structure. Since, our JSON API returns an array of dictionaries we use [[String:Any]] as our destination data structure type.
The main problem with using dictionaries is that the keys are in string format and they can be misspelled. Another problem is that if you use the key 100 places and later that key changes then you will have to update the key in all of those 100 places. The solution is to use a concrete class which can represent the JSON model.
JSON Model Classes:
Instead of dictionaries which depends on string keys, model classes are a better option since they are strongly typed and also provides easy way to modify the properties at once place. The class definition is shown below:
Now, we can replace our dictionaries code with the following:
A little better than the dictionaries but now we have too much code in our callback function. We can move the initialization part into a custom Pokemon initializer as shown below:
This makes our callback function leaner as shown below:
Looks great! But we are not done yet! The for-loop can be replaced by the map or flatMap functions which are available on Swift collections.
Much better and concise!
The key-value mapping part that we performed manually inside the init method can also be replaced by making a call to the setValueForKeys function which is available on the NSObject object.
Since, setValuesForKeys uses key-value coding for types represented in Objective-C we cannot use Double! or Double?. That is why we have removed nullable types and initialized them with some default values.
Be careful when using setValueForKeys function as if the key is not found it will throw an exception. This can be the case if you are not control of the API and owner of the API is sending JSON back in their own format. For each key that is not found in the receiving object setValue for undefined key is fired.
Currently, we have only looked at consuming simple JSON. But life is not so simple is it! Lets look at how we can consume a nested JSON structure. We will be using the JSON PlaceHolder Website which returns dummy JSON data. You can use this link to see the JSON structure we will be working with.
Our Users JSON structure is comprised of the following sub structures.
Our first step would be to create custom classes for each of our structure and just like the Pokemon initializer, create an initializer that will take dictionary as the parameter and populate the required properties.
The usage is shown below:
In this post we did not use any JSON parsing library and relied on the already available API’s in the iOS framework. For simple apps, which are not returning complicated nested data it would be fine but as you hit more complicated apps then it is best to use third party libraries to help you parse the JSON response.
In the next post I will cover few of the popular JSON parsing libraries and how they can make your life easier when consuming complicated JSON structure.