lambda-kotlin-request-router alternatives and similar libraries
Based on the "Web" category.
Alternatively, view lambda-kotlin-request-router alternatives based on common mentions on social networks and blogs.
-
javalin
DISCONTINUED. A simple and modern Java and Kotlin web framework [Moved to: https://github.com/javalin/javalin] -
apollo-android
:rocket: A strongly-typed, caching GraphQL client for the JVM, Android, and Kotlin multiplatform. -
http4k
The Functional toolkit for Kotlin HTTP applications. http4k provides a simple and uniform way to serve, consume, and test HTTP services. -
skrape.it
A Kotlin-based testing/scraping/parsing library providing the ability to analyze and extract data from HTML (server & client-side rendered). It places particular emphasis on ease of use and a high level of readability by providing an intuitive DSL. It aims to be a testing lib, but can also be used to scrape websites in a convenient fashion. -
hexagon
Hexagon is a microservices toolkit written in Kotlin. Its purpose is to ease the building of services (Web applications or APIs) that run inside a cloud platform. -
firefly
Firefly is an asynchronous web framework for rapid development of high-performance web application. -
tekniq
A framework designed around Kotlin providing Restful HTTP Client, JDBC DSL, Loading Cache, Configurations, Validations, and more -
Pellet
An opinionated, Kotlin-first web framework that helps you write fast, concise, and correct backend services 🚀. -
bootique-kotlin
DISCONTINUED. RETIRED. Provides extension functions and features for smooth development with Bootique and Kotlin. -
Zeko-RestApi
Asynchronous web framework for Kotlin. Create REST APIs in Kotlin easily with automatic Swagger/OpenAPI doc generation -
komock
KoMock - Simple HTTP/Consul/SpringConfig http server framework written in Kotlin. Wiremock use cases -
voyager-server-spring-boot-starter
Easily create REST endpoints with permissions (access control level) and hooks includeded
InfluxDB - Purpose built for real-time analytics at any scale.
* Code Quality Rankings and insights are calculated and provided by Lumnify.
They vary from L1 to L5 with "L5" being the highest.
Do you think we are missing an alternative of lambda-kotlin-request-router or a related project?
README
lambda-kotlin-request-router
A REST request routing layer for AWS lambda handlers written in Kotlin.
Goal
We came up lambda-kotlin-request-router
to reduce boilerplate code when implementing a REST API handlers on AWS Lambda.
The library addresses the following aspects:
- serialization and deserialization
- provide useful extensions and abstractions for API Gateway request and response types
- writing REST handlers as functions
- ease implementation of cross cutting concerns for handlers
- ease (local) testing of REST handlers
Reference
Getting Started
To use the core module we need the following:
repositories {
maven { url 'https://jitpack.io' }
}
dependencies {
implementation 'io.moia.lambda-kotlin-request-router:router:0.9.7'
}
Having this we can now go ahead and implement our first handler. We can implement a request handler as a simple function. Request and response body are deserialized and serialized for you.
import io.moia.router.Request
import io.moia.router.RequestHandler
import io.moia.router.ResponseEntity
import io.moia.router.Router.Companion.router
class MyRequestHandler : RequestHandler() {
override val router = router {
GET("/some") { r: Request<String> -> ResponseEntity.ok(MyResponse(r.body)) }
}
}
Content Negotiation
The router DSL allows for configuration of the content types a handler
- produces (according to the request's
Accept
header) - consumes (according to the request's
Content-Type
header)
The router itself carries a default for both values.
var defaultConsuming = setOf("application/json")
var defaultProducing = setOf("application/json")
These defaults can be overridden on the router level or on the handler level to specify the content types most of your handlers consume and produce.
router {
defaultConsuming = setOf("application/json")
defaultProducing = setOf("application/json")
}
Exceptions from this default can be configured on a handler level.
router {
POST("/some") { r: Request<String> -> ResponseEntity.ok(MyResponse(r.body)) }
.producing("application/json")
.consuming("application/json")
}
Filters
Filters are a means to add cross-cutting concerns to your request handling logic outside a handler function. Multiple filters can be used by composing them.
override val router = router {
filter = loggingFilter().then(mdcFilter())
GET("/some", controller::get)
}
private fun loggingFilter() = Filter { next -> {
request ->
log.info("Handling request ${request.httpMethod} ${request.path}")
next(request) }
}
private fun mdcFilter() = Filter { next -> {
request ->
MDC.put("requestId", request.requestContext?.requestId)
next(request) }
}
}
Permissions
Permission handling is a cross-cutting concern that can be handled outside the regular handler function. The routing DSL also supports expressing required permissions:
override val router = router {
GET("/some", controller::get).requiringPermissions("A_PERMISSION", "A_SECOND_PERMISSION")
}
For the route above the RequestHandler
checks if any of the listed permissions are found on a request.
Additionally we need to configure a strategy to extract permissions from a request on the RequestHandler
.
By default a RequestHandler
is using the NoOpPermissionHandler
which always decides that any required permissions are found.
The JwtPermissionHandler
can be used to extract permissions from a JWT token found in a header.
class TestRequestHandlerAuthorization : RequestHandler() {
override val router = router {
GET("/some", controller::get).requiringPermissions("A_PERMISSION")
}
override fun permissionHandlerSupplier(): (r: APIGatewayProxyRequestEvent) -> PermissionHandler =
{ JwtPermissionHandler(
request = it,
//the claim to use to extract the permissions - defaults to `scope`
permissionsClaim = "permissions",
//separator used to separate permissions in the claim - defaults to ` `
permissionSeparator = ","
) }
}
Given the code above the token is extracted from the Authorization
header.
We can also choose to extract the token from a different header:
JwtPermissionHandler(
accessor = JwtAccessor(
request = it,
authorizationHeaderName = "custom-auth")
)
:warning: The implementation here assumes that JWT tokens are validated on the API Gateway. So we do no validation of the JWT token.
Protobuf support
The module router-protobuf
helps to ease implementation of handlers that receive and return protobuf messages.
implementation 'io.moia.lambda-kotlin-request-router:router-protobuf:0.9.7'
A handler implementation that wants to take advantage of the protobuf support should inherit from ProtoEnabledRequestHandler
.
class TestRequestHandler : ProtoEnabledRequestHandler() {
override val router = router {
defaultProducing = setOf("application/x-protobuf")
defaultConsuming = setOf("application/x-protobuf")
defaultContentType = "application/x-protobuf"
GET("/some-proto") { _: Request<Unit> -> ResponseEntity.ok(Sample.newBuilder().setHello("Hello").build()) }
.producing("application/x-protobuf", "application/json")
POST("/some-proto") { r: Request<Sample> -> ResponseEntity.ok(r.body) }
GET<Unit, Unit>("/some-error") { _: Request<Unit> -> throw ApiException("boom", "BOOM", 400) }
}
override fun createErrorBody(error: ApiError): Any =
io.moia.router.proto.sample.SampleOuterClass.ApiError.newBuilder()
.setMessage(error.message)
.setCode(error.code)
.build()
override fun createUnprocessableEntityErrorBody(errors: List<UnprocessableEntityError>): Any =
errors.map { error ->
io.moia.router.proto.sample.SampleOuterClass.UnprocessableEntityError.newBuilder()
.setMessage(error.message)
.setCode(error.code)
.setPath(error.path)
.build()
}
}
Make sure you override createErrorBody
and createUnprocessableEntityErrorBody
to map error type to your proto error messages.
Open API validation support
The module router-openapi-request-validator
can be used to validate an interaction against an OpenAPI specification.
Internally we use the swagger-request-validator to achieve this.
This library validates:
- if the resource used is documented in the OpenApi specification
- if request and response can be successfully validated against the request and response schema
- ...
testImplementation 'io.moia.lambda-kotlin-request-router:router-openapi-request-validator:0.9.7'
val validator = OpenApiValidator("openapi.yml")
@Test
fun `should handle and validate request`() {
val request = GET("/tests")
.withHeaders(mapOf("Accept" to "application/json"))
val response = testHandler.handleRequest(request, mockk())
validator.assertValidRequest(request)
validator.assertValidResponse(request, response)
validator.assertValid(request, response)
}
If you want to validate all the API interactions in your handler tests against the API specification you can use io.moia.router.openapi.ValidatingRequestRouterWrapper
.
This a wrapper around your RequestHandler
which transparently validates request and response.
private val validatingRequestRouter = ValidatingRequestRouterWrapper(TestRequestHandler(), "openapi.yml")
@Test
fun `should return response on successful validation`() {
val response = validatingRequestRouter
.handleRequest(GET("/tests").withAcceptHeader("application/json"), mockk())
then(response.statusCode).isEqualTo(200)
}