How to build REST API with Arrow, Ktor and requery in Kotlin

Posted

November 8, 2019

Authors
No items found.
Series

In one of our projects, we have decided to give a try to Kotlin programming language for our backend service. Kotlin is well known among Android Developers as an alternative to Java. It is also the language that is supported by Spring, which is a well known Java Framework. Ktor, on the other hand, is Kotlin library which can be used to create asynchronous HTTP servers and clients. We have also found Arrow— Kotlin library that implements common concepts from functional programming like typeclasses and effects. Unfortunately, Ktor is not functional and is based on suspend functions. In this tutorial, we will show how to integrate these two libraries and make a sample REST API in a functional way.

We will use the latest version of Arrow (0.10.0), which contains `IO.suspend()` function used to integrate with Kotlin `suspend` functions. The final code can be found at GitHub: https://github.com/siilisolutions-pl/arrow-ktor-blog-entry. In this repository, you can also find an earlier solution with Arrow 0.9.0, which is a little bit more complicated because of the lack of `IO.suspend()` function. Let’s go into the code now.

Integrate Ktor with Arrow

Let’s define a sample entity:

GIST: https://gist.github.com/rpiotrow/4290b79bd6aca6295a8f4f53b40f049f.js

Next, there will be Ktor server returning static JSON content:

GIST: https://gist.github.com/rpiotrow/af0215676f0ffe30085963b38ff59aaa.js

There is a configuration for JSON serialization (using Jackson library) and one endpoint (`”/employees”`) returning a list of employees. Let’s extract data access to a separate class and use Arrow’s effect:

GIST: https://gist.github.com/rpiotrow/59cf6f24b27b18eee3b42ba02dedd77f.js

Kotlin does not have higher kinded types, they are emulated in Arrow with `Kind<F, A>` (for specific `F` we need to use `For*` classes like `ForIO` for `IO` to be able to compile the code, e.g. `Kind<ForIO, List<Employee>>`). There exists conversion functions, so `IO<List<Employee>>` for the compiler is the same as `Kind<ForIO, List<Employee>>`.

If we now use the above repository directly:

GIST: https://gist.github.com/rpiotrow/51b0883feec559b2bacfcee7a2ce73a5.js

it won’t work since we pass to Ktor list of employees wrapped in `IO`. Obviously, we can invoke it:

GIST: https://gist.github.com/rpiotrow/6846e4e31f444a7825ce9368e60e37e9.js

but this is not very elegant and if we would like to extract routing to a separate class that will be stuck to the `IO` from Arrow. What we want is to transform the `IO` into suspend function that will be invoked by Ktor in an appropriate time. To make it in a generic way we will define `Suspendable` typeclass and provide an implementation of it for `IO`:

GIST: https://gist.github.com/rpiotrow/f6003b08780a3ae943ad5f08a87ea440.js

`Suspendable<F>` is a typeclass that tells us we can transform effect `F` into the suspended function which returns value from `F`. We define an instance of `Suspendable` for `IO` as function in the companion object. This is a standard way how typeclasses are defined in Arrow (in Arrow it is implemented with `@extension` annotation and annotation processor which generates code; However, we do not want to unnecessarily complicate this sample code). Implementation is trivial, since we invoke ready to use function of `IO` monad (introduced in Arrow 0.10.0).

Now let’s extract our routing, make it generic and use `Suspendable` typeclass:

GIST: https://gist.github.com/rpiotrow/d7d872edfe0c78a1f0988645f014cd20.js

We can now use it in our application:

GIST: https://gist.github.com/rpiotrow/6783b8eabe0aa80547763b7f95eb6557.js

Ktor is now integrated with functional `IO` monad from Arrow library.

Routing class needs only the implementation of repository and implementation of `Suspendable` for `F`, which means that we can make unit tests quite easily using below code:

GIST: https://gist.github.com/rpiotrow/811c59438a2cf63f7a71e8f0b8f66b72.js

We can also make some more “layers” between repository and routing, which all will be based on `F` (it can be a service layer, and/or a validation layer), and test them in isolation using any implementation of `F` that will work best in unit tests.

Accessing database

Since we already have a web layer, let’s implement repository that will access a real SQL database. Time to use requery library:

GIST: https://gist.github.com/rpiotrow/6217736319c273426fcf8cdca86968fe.js

We have used `MonadDefer` from Arrow to delay synchronous operation and KotlinEntityDataStore from requery that will be configured below. First, some annotation and mark interface is needed in the entity class:

GIST: https://gist.github.com/rpiotrow/bf45edc6e4de7c52424c2752b768f64a.js

All we need to change in the application is adding already mentioned configuration for requery and change the usage of `IOEmployeeRepository` to `DeferEmployeeRepository`. Since `IO` implements `MonadDefer` there is nothing we need to do here (besides passing proper typeclass instance to repository constructor).

Let’s make a configuration of requery with H2 in-memory database with some sample data:

GIST: https://gist.github.com/rpiotrow/4ce02eafe0698fb8707184bf3d2d4c79.js

Below you can find the updated server using the new repository.

GIST: https://gist.github.com/rpiotrow/fbfdc6235445190cba4a3373ad79b972.js

Since requery supports Java Rx2 we can also make different implementation of the repository with `Single` as our `F` type:

GIST: https://gist.github.com/rpiotrow/8774a0e739c17b2a83bb4383e494f7a2.js

Here, we do not need to use `MonadDefer`, since `Single` is already asynchronous, but we need to implement `Suspendable` for `SingleK`(Arrow’s wrapper for Single from Java Rx 2.0):

GIST: https://gist.github.com/rpiotrow/363c295cabdd4a19bdf9d8f26c56834e.js

Usage of `suspendCoroutine` function is a way to transform the callback API method to `suspend` method. Here we invoke `subscribe` function from Java Rx2 `Single` class and use the result callback for transformation into `suspend` function.

Finally, we can use the same routing implementation with two different repository implementations:


GIST: https://gist.github.com/rpiotrow/4c1e1d22f605466b1e4279d5fa4019d7.js

Summary

We have created sample REST API with Ktor, Arrow and requery in a functional way. `Suspendable` typeclass integrated nicely functional code with asynchronous HTTP server. Requery helped us to make non-blocking access to the SQL database. Full source code can be found at https://github.com/siilisolutions-pl/arrow-ktor-blog-entry.

Thanks to Simon Vergauwen, Bob Glamm, Anton Spaans and Paco Estevez from #arrow on https://kotlinlang.slack.com/

About the authors
No items found.

Latest POSTS

April 15, 2021

Driving down automotive costs for fully digital HMI experience

March 31, 2021

Designer’s hints for accelerating the design to target workflow with Qt Bridge for figma

March 31, 2021

Future of voice interfaces in the next-gen Auto HMI

August 28, 2020

The Future of Automotive Design