6
votes

My question is about the big picture behind routing functionality in Ktor; and scalability when it comes to design an API with large number of routes.

If I create an app like this:

import io.ktor.application.*
import io.ktor.response.*
import io.ktor.request.*
import io.ktor.server.engine.embeddedServer
import io.ktor.server.netty.Netty

fun Application.routingExample() {
 intercept(ApplicationCallPipeline.Call){
   if (call.request.uri == "/") call.respondText("User call for /")
 }
}

fun main(args: Array<String>) {
    embeddedServer(Netty, 8080, watchPaths = listOf("Routing"), module = Application::routingExample).start()
}

Which is ok if I have an api/app with low number of routes. However in what style I should scale this approach for large number of routes (e.g., 30 routes and controller functions).

I would have a number of choices:

A large routing function: I would have a large Application.routingExample function that would hold all the routes, so I don't need to update the main.

A large main function: Would have a large function that would hold the calls to different smaller functions; but it would be repetitive; as for an API I want to serve them in the same port.

So my question is about the coding style: is there a way to to factorize the routing controller relationship?

1

1 Answers

12
votes

First, there is a sophisticated routing feature, so you don't need to compare request URIs.

Second, since the routing is a DSL and thus just code, you can extract functions and organize your code in whatever manner you like. One example is KotlinConf backend application. Source code is available here: https://github.com/JetBrains/kotlinconf-app/blob/master/backend/src/org/jetbrains/kotlinconf/backend/Api.kt

It looks like this:

fun Routing.api(database: Database, production: Boolean) {
    apiKeynote(database, production)
    apiRegister(database, production)
    apiAll(database, production)
    apiSession(database, production)
    apiVote(database, production)
    apiFavorite(database, production)
    wsVotes(database, production)
}

Each function is an extension to Routing and defines its own set of API endpoints, something like this:

fun Routing.apiFavorite(database: Database, production: Boolean) {
    route("favorites") {
        get { … }
        post { … }
        delete { … }
    }
}

You can put them in different files, folders or packages, along with the business logic, support systems, etc.