Functional Handlers

With this module, requests can be handled in a functional manner, reducing the boilerplate code to be written by a web application developer.

Hosting an API

To host an API using this framework you can create an Inline handler and add your operations as needed.

Kotlin
import org.genhttp.engine.internal.Host

import org.genhttp.modules.apibrowsing.addRedoc
import org.genhttp.modules.functional.*
import org.genhttp.modules.layouting.Layout
import org.genhttp.modules.openapi.addOpenApi
import org.genhttp.modules.security.CorsPolicy

import java.util.concurrent.ConcurrentHashMap

data class Book(val id: Int, val title: String)

suspend fun main() {
    val books = ConcurrentHashMap<Int, Book>()

    val bookService = Inline.create()
        // GET http://localhost:8080/books/?page=1&pageSize=20
        .get { page: Int, pageSize: Int ->
            books.values.sortedBy { it.id }.drop(maxOf(page - 1, 0) * pageSize).take(pageSize)
        }
        // GET http://localhost:8080/books/4711
        .get(":id") { id: Int -> books[id] }
        // PUT http://localhost:8080/books/
        .put { book: Book -> book.also { books[it.id] = it } }
        // POST http://localhost:8080/books/
        .post { book: Book -> book.also { books[it.id] = it } }
        // DELETE http://localhost:8080/books/4711
        .delete(":id") { id: Int -> books.remove(id) }

    val api = Layout.create()
        .add("books", bookService)
        .add(CorsPolicy.permissive())
        .addOpenApi() // http://localhost:8080/openapi.json
        .addRedoc() // http://localhost:8080/redoc/

    Host.create()
        .handler(api)
        .development()
        .run()
}

The handlers are suspend lambdas that declare the types of their parameters ({ id: Int -> ... }), as genhttp-kt reads the names and types of the parameters to map them to the request. The overloads taking lambdas with parameters are extension functions, so import org.genhttp.modules.functional.* is required - without it, the compiler only finds the overloads without parameters and reports a type mismatch.

Kotlin does not allow annotations or default values on the parameters of a lambda. Handlers that need them (such as @FromBody or an optional query parameter) are declared as functions and passed as a function reference:

Kotlin
import org.genhttp.modules.functional.*

// GET http://localhost:8080/?page=2 responds with "Page 2 with 20 books"
fun listBooks(page: Int = 1, pageSize: Int = 20): String = "Page $page with $pageSize books"

val books = Inline.create()
    .get(::listBooks)

Further Resources

The following capabilities are shared by various application frameworks: