hello guys, is there any documentation or example ...
# ktor
a
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.
c
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.
n
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:
Copy code
// 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
get
on
Location.GetId
which stuffs the argument into the `Location`'s string (replacing
{id}
) and issues the GET request using your client of choice (Ktor?). The server module has an extension function
get
on
Route
which takes a
Location.GetId
instead of a raw string. For convenience, I have the
body
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
call.respond
.
Both functions are
inline
with reified types, so that the type parameters used when creating the
Location
can be used for serialization and deserialization.
k
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,
n
@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.