Introduction
API Viaduct is a serverless RESTful API and router written in Kotlin for AWS Lambda.
Inspired by my earlier project Cantilever, I wanted to create a more lightweight and flexible API framework for AWS Lambda. This project is a work in progress and is not yet ready for production use.
RESTful routes are defined using a Kotlin DSL, and the library uses Kotlinx Serialization for JSON (de)serialization. The project is built using Gradle and the AWS SDK for Kotlin.
The library supports route grouping, authentication, all the main REST methods, and more. There is a rudimentary OpenAPI specification generator, and middleware or filters will be added in the future. While the router defaults to JSON, it is possible to specify other content types such as text, YAML or any others supported by kotlinx.serialization.
The library does not currently support multipart form uploads, nor URL query parameters.
Example
class MyRouter : LambdaRouter() {
override val router = lambdaRouter {
// a simple get request handler
get("/hello") { _: Request<Unit> ->
Response.OK("Hello, world!")
}
// a simple POST request handler, expecting a JSON body for a data class of type 'Thingy'
post("/new") { req: Request<Thingy> ->
val body = req.body
Response.OK("You sent: ${body.name}")
}
// route grouping
group("/group") {
get("/test", handler = { _: Request<Unit> -> Response.ok(body = "This route was /group/test") }).supplies(
MimeType.plainText
)
}
// basic authentication support (there is an authentication interface to implement)
auth(BasicFakeAuthorizer()) {
get("/secure") { _: Request<Unit> ->
Response.ok("Secure route")
}.supplies(MimeType.plainText)
}
}
}
OpenAPI Specifications
APIViaduct supports a limited but useful subset of the OpenAPI 3.1.0 specification and can automatically generate an openapi.yaml file from the route definitions. Generation happens at compile time. The router DSL adds documentation to routes. The system does not provide a SwaggerUI implementation.
To add OpenAPI specifications to your project, add the following block to your lambda router:
override val router = lambdaRouter {
// Document-level metadata: the info/servers sections of the generated document.
openApi {
info {
title = "Book Library API"
version = "1.0.0"
description = "A small CRUD API for managing a library of books."
contact(name = "Library Team", email = "library@example.com")
license(name = "Apache-2.0", identifier = "Apache-2.0")
}
server("https://api.example.com", "production")
}
//...
}
To add additional documentation and specifications to a given route, add the .spec { } block to the route declaration:
get("", BookHandlers::list)
.spec {
summary = "List books"
description = "Returns every book in the library, optionally filtered by author or genre."
operationId = "listBooks"
tags("books")
queryParam("author", "Only return books by this author")
queryParam("genre", "Only return books of this genre")
queryParam("limit", "Maximum number of books to return")
response(200, "The matching books")
}
Lambda cold start
I am migrating this project to GraalVM, to improve cold start times. The initial implementation is complete, but I need to test it thoroughly.