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.
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:
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: