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

Rafal Piotrowski
siili_auto
Published in
4 min readNov 8, 2019

Introduction

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:

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

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:

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:

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

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:

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:

We can now use it in our application:

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:

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:

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:

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:

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

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

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

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:

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/

--

--

Rafal Piotrowski
siili_auto

Developer focused on functional programming in Scala and Kotlin.