JSON Parsing in Swift with Generics

Introduction

Most of the time, the mobile apps are calling REST services to get and display the latest data to their users. We’ve already covered the networking part – making requests to the server and getting response. After we get the response, we need to check its Content-Type, and based on that, parse the data so we can extract the needed information. Most of the apps are using JSON as a way of communication with the REST services, because it’s simple, lightweight and easy to understand. There are cases where there is a need of more structured exchange of information, which JSON cannot provide. In those cases, usually XML and SOAP are used, but we will not go in any details about them in this post. We will see how we can parse an example JSON with Swift, by using Generics, which are one of the most powerful features of Apple’s new language.

Generics are very helpful when different kinds of types need to do the same set of functions. It encourages developers to create reusable functions which will work with any type, without the need of duplication or to create an abstract type when there is no logical way to connect the distinct types.

JSON Parsing example

Usually in mobile app development, we don’t have much control over the design of the REST services and their format. They are part of some complex systems and most of the time we design our parsers based on what the server provides. Let’s see two example JSON responses:

[{
 "type": "our_app_menu",
 "subtype": "navigation",
 "items": [{
 "type": "menu",
 "subtype": "category",
 "title": "Sample Title",
 "feedUrl": "http://example.com/contents/1"
 }, {
 "type": "menu",
 "subtype": "category",
 "title": "Sample Title",
 "feedUrl": "http://example.com/contents/2"
 }]
}]
[{
 "type": "our_app_post",
 "subtype": "entry",
 "title": "Test Post",
 "img": {
	 "src": "http://example.jpg",
      	 "width": 1280,
 	 "height": 880
	}
}]

The first one returns the menu items in the app. It can be a hamburger menu, some collection view on a home page or something else. Each menu item contains a feed url, from which the posts are taken. The second JSON response is for the posts retrieved on those urls. As you can see, both of them contain type and subtype, and those identify what we need to extract from the JSON (those are used for some identification on the backend as well). So basically, the parsing should recognize the types and subtypes that we need, for every entry, get only those items and create models that later will be used in the code.

Let’s add additional requirement to our app – whenever the network request fails, we should use some locally saved cached responses as a fallback. Also, apart from the posts, there are other types we need to show in the app – FAQs, users etc., and all of those follow the same type/subtype matching principle and similar JSON formats.

Our solution should be generic enough to express all of the type similarities, constraints and requirements. Let’s start with a parsing protocol which will provide an overview of what we might need:

Screen Shot 2016-08-28 at 21.24.25.png

The first two methods and variable are needed for the caching requirement when there’s no internet connection. The next two variables (itemType and itemSubtype) are used for the matching of the type in the JSON response. The extractTypesFromDictionary creates a type out of the dictionary response and the typeArrayFromResponse is the general method which receives the response object, serializes the JSON to a dictionary and calls the extractTypesFromDictionary to get the needed type. Note the usage of generics in these methods, marked with T. We are also using type constraints (<T where T: Decodable>) to restrict the types passed to these methods to the ones conforming to the Decodable protocol.

The Decodable protocol is from the awesome functional JSON parsing library Argo. I highly recommend for reading the three blog posts dedicated to the creation of this library, where the functional concepts and ideology of Argo are explained in depth. Back to the Decodable protocol – each type that conforms to this protocol needs to implement the decode method, where you specify which key from the JSON conforms to which property:

Screen Shot 2016-08-28 at 21.26.22

Note: The custom operators <^>, <| and <*> are explained in the posts about the ideology of Argo and I will not go into any details about those in this post.

Next, let’s start implementing the Parseable protocol. There are things in this protocol that are common to all its possible implementers, which means we can provide some default implementations in a protocol extension:

Screen Shot 2016-08-28 at 21.27.46

The loadLocalArray is pretty straightforward – it loads a local file from the bundle for the given type and it calls the parseResponse method. If you want to always have the latest successful response you can update the method to load the response from a path in the file system for the app, instead of from the bundle.

The parseResponse method is the place where all of the serialization, matching and parsing is done. After we get an array of dictionaries from the response body, we use a combination of map -> filter -> reduce to get the data we need. We could’ve done this with for loop and some if statements, however this looks much better and it’s also less error prone. The matching is done in the filter function, where we check against the itemType and itemSubtype whether the next entry in the array is what we need. Afterwards we call the map function, to transform each dictionary to the generic type we need. The extractTypesFromDictionary is type specific, so we can’t provide a default implementation – each type will provide its own. The reduce part just flattens the array of arrays.

The typeArrayFromResponse is also pretty simple, it just checks whether the request was successful and based on that, it either parses the new response or loads the local array.

Now, let’s see how one possible implementation of this protocol might look like:

Screen Shot 2016-08-28 at 21.29.39.png

In the extractTypesFromDictionary, we just check whether there is a key for the menu items in the response dictionary and if it is, we try to decode it using Argo. If the decoding succeeds, we have new category object attached to the items, otherwise we return nil.

If other types have the same format, we can also abstract away this method, where the REST.MenuItems will be provided by each type. Otherwise each type will provide its own implementation of this method. And this is everything that needs to be done in a protocol implementation – we’ve made generic functions in the parsing protocol which work for every type.

This is a simple example and tied to a problem domain (strictly defined format and matching requirement), but the same principle – combining Generics with Protocols, can be used in much more complex scenarios. The biggest takeaway is the true power of generics and how they can improve the way we write code.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s