Sharing Retrofit With Your Backend

Josh Feinberg
2 min readMar 4, 2020

I gave a talk about how to build a backend and frontend while sharing the API routes to make sure they stay consistent. The key trick behind this a file that contained a bunch of string constants. This way the same route names could be accessed by both the Ktor backend module and my android app.

const val SICKNESS_POST = "throwup"
const val SICKNESS_GET = "throwup"
const val STATS_GET = "stats"
const val WEIGHT_POST = "weight"
const val WEIGHT_GET = "weight"

It was a simple solution and worked for a small project but I had my concerns.

The first problem was those names didn’t enforce anything. I could screw up and put the POST in the GET route or vice-versa and I would have no way of knowing.

The second problem was scalability of the constants for a larger project. This worked for five endpoints, but I couldn’t see this working for much more than that.

In search of a solution, I came across ktor-retrofit, a Ktor plugin that parses your retrofit interface and builds the ktor routes. It was a perfect fit. I was already using retrofit for the app and having a consistent shared interface was more guaranteed to keep everything in sync.

Building the Interface

Originally in my app module I had a single interface that implemented every route from my backend. The Ktor app I had currently setup had controllers for groups of endpoints so I decided to split this up into multiple interfaces. Since retrofit 2.7.0 you are able to have your service interfaces extend other interfaces which worked well with this setup. A fix for that was also in ktor-retrofit 0.1.2.

If you are going to use this in a shared module you will still need to import either ktor-retrofit or retrofit as a dependency to use the annotations. As another note, all your methods must be suspend functions for this to work with ktor-retrofit.

Setting Up Ktor

Now that the interface is defined, it was time to hook it up to ktor. Since this was using retrofit in the app module no changes were needed there.

The first step was to switch my controllers to implement the individual service interfaces. Since they are simply suspend functions I was able to have it return my data and it just worked.

Once I had all those controllers setup, I needed to create a wrapper as ktor-retrofit needed to know where it could find all the implementations. With kotlin’s succinctness this ended up being really clean.

Then all it took was a quick hook up using a helper function to find the kodein handled singletons and it was done.

Once that was all hooked up I was able to deploy my server again to google cloud. One it was up, the app still worked perfectly and we were good to go.

Once that was all hooked up I was able to deploy my server again to google cloud. One it was up, the app still worked perfectly and we were good to go!

--

--