Andre Stefanov

08/24/2021, 1:50 PM
hello guys, is there any documentation or example (or even a lib/framework) how to share ktor routes between server and client? i am building a multiplatform application with ktor jvm server, android app and a shared module. but jvm only example would already help a lot.


08/24/2021, 2:10 PM
I haven't used Ktor before, but in the Spring world I use HATEOAS as a way to provide the client a list of named links describing what's available. The link conforms to RFC-6570 which means using it build a url given required parameters is standard and I can even decide to change a path variable to a request parameter without affecting the client. I think I once saw a hateoas package for ktor. I haven't checked it our yet. In my view it is a powerful and standard way to tell the client what's available. The absence of a link means that function isn't available. The client needs to know the names of the links, the method and the parameters required. I usually have an entry point the provides all the 'global' named links and an API version. The client can request a version and if the requested version isn't supported you can provide an error.


08/24/2021, 8:11 PM
The general idea I used is to separate the route definitions out as data classes and define extension functions for Ktor server and Ktor client that translate those classes into regular Ktor client requests and Ktor server routes. The code that I wrote is proprietary to my employer and pretty specific to my use case, but the end result is like this:
// In the shared module:
data class Resource(val something: String)
val getResourceById = Location.GetId<Resource>("/resource/{id}")

// In the client module:
val resource = getResourceById.get("idHere")

// In the server module:
fun Routing.resourceController() {
  get(getResourceById) { id ->
    return resources.get(id)
💯 1
For the above code to work two functions are needed: The client module has an extension function
which stuffs the argument into the `Location`'s string (replacing
) and issues the GET request using your client of choice (Ktor?). The server module has an extension function
which takes a
instead of a raw string. For convenience, I have the
lambda accept the ID as a string and return the type specified when the location was defined. The extension function does the translation to create the regular Ktor route with
Both functions are
with reified types, so that the type parameters used when creating the
can be used for serialization and deserialization.

Kamil Kalisz

08/26/2021, 6:31 AM
I think that question was how to share API definitions between client and server without need external tools like swagger. Indeed it would be great if there would be possibility to have API contract is some common module that will be single source of truth for all projects. But for now I don’t have idea how to achieve that,


08/26/2021, 3:15 PM
@Kamil Kalisz, having the API contract in a common module is exactly what I was discussing. I've done it by defining the contract as values in the shared module, with the server and client each having code that knows how to turn those data classes into actual handlers and API requests.