Ktor 2.3.10 Help

Locations

Ktor provides a mechanism to create routes in a typed way, for both: constructing URLs and reading the parameters.

Add dependencies

To use Locations, you need to include the ktor-server-locations artifact in the build script:

implementation("io.ktor:ktor-server-locations:$ktor_version")
implementation "io.ktor:ktor-server-locations:$ktor_version"
<dependency> <groupId>io.ktor</groupId> <artifactId>ktor-server-locations-jvm</artifactId> <version>${ktor_version}</version> </dependency>

Install Locations

To install the Locations plugin to the application, pass it to the install function in the specified module. The code snippets below show how to install Locations...

  • ... inside the embeddedServer function call.

  • ... inside the explicitly defined module, which is an extension function of the Application class.

import io.ktor.server.application.* import io.ktor.server.locations.* // ... fun main() { embeddedServer(Netty, port = 8080) { install(Locations) // ... }.start(wait = true) }
import io.ktor.server.application.* import io.ktor.server.locations.* // ... fun Application.module() { install(Locations) // ... }

Define route classes

For each typed route you want to handle, you need to create a class (usually a data class) containing the parameters that you want to handle.

The parameters must be of any type supported by the Data Conversion plugin. By default, you can use Int, Long, Float, Double, Boolean, String, enums and Iterable as parameters.

URL parameters

That class must be annotated with @Location specifying a path to match with placeholders between curly brackets { and }. For example: {propertyName}. The names between the curly braces must match the properties of the class.

@Location("/list/{name}/page/{page}") data class Listing(val name: String, val page: Int)
  • Will match: /list/movies/page/10

  • Will construct: Listing(name = "movies", page = 10)

GET parameters

If you provide additional class properties that are not part of the path of the @Location, those parameters will be obtained from the GET's query string or POST parameters:

@Location("/list/{name}") data class Listing(val name: String, val page: Int, val count: Int)
  • Will match: /list/movies?page=10&count=20

  • Will construct: Listing(name = "movies", page = 10, count = 20)

Define route handlers

Once you have defined the classes annotated with @Location, this plugin artifact exposes new typed methods for defining route handlers: get, options, header, post, put, delete and patch.

routing { get<Listing> { listing -> call.respondText("Listing ${listing.name}, page ${listing.page}") } }

Build URLs

You can construct URLs to your routes by calling application.locations.href with an instance of a class annotated with @Location:

val path = application.locations.href(Listing(name = "movies", page = 10, count = 20))

So for this class, path would be "/list/movies?page=10&count=20"".

@Location("/list/{name}") data class Listing(val name: String, val page: Int, val count: Int)

If you construct the URLs like this, and you decide to change the format of the URL, you will just have to update the @Location path, which is really convenient.

Subroutes with parameters

You have to create classes referencing to another class annotated with @Location like this, and register them normally:

routing { get<Type.Edit> { typeEdit -> // /type/{name}/edit // ... } get<Type.List> { typeList -> // /type/{name}/list/{page} // ... } }

To obtain parameters defined in the superior locations, you just have to include those property names in your classes for the internal routes. For example:

@Location("/type/{name}") data class Type(val name: String) { // In these classes we have to include the `name` property matching the parent. @Location("/edit") data class Edit(val parent: Type) @Location("/list/{page}") data class List(val parent: Type, val page: Int) }
Last modified: 02 April 2024