Multi-platform mobile networking libraries with Ktor

Andrea Prearo
Granular Engineering
3 min readJul 13, 2020
Photo by Mike Marquez on Unsplash

In this post I’m going to illustrate how it’s possible to leverage Ktor to create a shared mobile library that wraps a REST API. The code I’m going to present here can be hosted inside a Kotlin Multi Platform (a.k.a. KMP) project and consumed by any Android and iOS app. For the sake of this post I’m going to target a simple and publicly available API: JSONPlaceholder.

JSONPlaceholder API Overview

The JSONPlaceholder API is rather simple and provides online fake data. Here are the available resources:

Each one of the above resources returns a predefined number of JSON objects containing fake data representing an entity corresponding to the resource name (i.e.: posts, comments, …).

Wrapping the /users resource

To limit the scope of this post I’m going to show how it’s possible to create a wrapper for the /users resource. Such a resource returns the most complex data, which uses nested JSON objects, among the resources provided by JSONPlaceholder. All remaining resources can be wrapped the same way and with less effort since they don’t return nested objects.

Creating the User model

The /users resource returns an array of JSON objects representing fake users. Each user object has the structure shown in the following snippet:

We can take advantage of Kotlin’s @Serializable annotation to create classes to model each user object returned in the JSON. In order to achieve that we are going to need a top level User class and a few nested classes (Address, Company and Geolocation):

Retrieving and parsing JSON data

Now that we have our serializable models in place we will create a class that encapsulates the JSONPlaceholder API functionality. The full code is listed below:

The /users resource is modeled using an enum class to encapsulate its details.

Our workhorse is the Api class: It uses Ktor’s default HttpClient which will allows us to make HTTP requests. HttpClient is highly configurable: In this particular case we are instructing it to use KotlinxSerializer to deserialize any HTTP response:

========================================

NOTE

KotlinxSerializer uses strict mode parsing by default. This means that the deserialization will fail if it encounters unknown or malformed keys when parsing the JSON payload. In our scenario, this is not an issue because our models are built to capture all the properties of the JSON object they represent.

The default strict mode parsing behavior can be turned off by explicitly setting the serializer configuration. In earlier versions of KotlinxSerializer, the strict mode parsing behavior was determined by a single constructor argument: strictMode. The current version of KotlinxSerializer, instead, provides three constructor arguments that allow to relax the parsing requirements:

The default strict mode parsing behavior can be turned off by explicitly setting the serializer configuration as follows:

========================================

The setupCall helper method allows us to easily build an url instance given the desired endpoint:

The created url instance will be used by Ktor to make an HTTP call:

Ktor’s HttpClient will infer User as the class for deserializing the HTTP response and will try to parse the JSON response and return the result as a List<User> instance.

Each remaining JSONPlaceholder resource (i.e.: posts, comments, …) can be wrapped using the same approach illustrated above.

Conclusion

You can find the full code for wrapping JSONPlaceholder here.

In this post we examined how it’s possible to leverage Ktor to nicely wrap a REST API. In particular we saw how we can use Ktor’s HttpClient to make HTTP requests and KotlinxSerializer to deserialize HTTP responses into Kotlin serializable classes.

In the next post we’re going to take a look at how we can create unit tests for HTTP calls.

--

--

Andrea Prearo
Granular Engineering

Experienced iOS Engineer and Software Craftsman with extensive expertise in building reusable libraries and components to scale development teams and products.