Last active
July 27, 2018 15:45
-
-
Save mvniekerk/c36a65d667581bb43d71f4665520931f to your computer and use it in GitHub Desktop.
Vert.x Web Router / Kotlin infix helper methods
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import io.vertx.core.Vertx | |
import io.vertx.ext.web.Router | |
import za.co.koperfontein.amapogo.safetyq.mongo.MONGO_ENTRY_PAGE_ENABLE_DISABLE | |
import za.co.koperfontein.amapogo.safetyq.mongo.MONGO_ENTRY_PAGE_GET | |
import za.co.koperfontein.amapogo.safetyq.mongo.MONGO_ENTRY_PAGE_VALUES_UPDATE | |
// Example usage | |
class PageHttpRoutes(router: Router, vertx: Vertx): RegisterHttpRoutes(router, vertx) { | |
override fun registerRoutes() { | |
// GET example using path params | |
this get "/api/entry/:entryId/pages/:pageName" pathParams mapOf("entryId" to "id", "pageName" to "page") from MONGO_ENTRY_PAGE_GET | |
// PATCH example using path params and body params | |
this patch "/api/entry/:entryId/pages/:pageName/values" pathParams mapOf("entryId" to "id", "pageName" to "page") bodyParams | |
mapOf("author" to "creator") to MONGO_ENTRY_PAGE_VALUES_UPDATE | |
// PUT example that sends path and body params as is to the downstream event bus listener | |
this put "/api/entry/:entryId/pages/:pageName/enabled" pathParams mapOf("entryId" to "id", "pageName" to "page") to MONGO_ENTRY_PAGE_ENABLE_DISABLE | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
abstract class RegisterHttpRoutes(val router: Router, val vertx: Vertx) { | |
abstract fun registerRoutes() | |
infix fun get(address: String): RequestHandler = RequestHandler(address, vertx, router, "GET") | |
infix fun post(address: String): RequestHandler = RequestHandler(address, vertx, router, "POST") | |
infix fun patch(address: String): RequestHandler = RequestHandler(address, vertx, router, "PATCH") | |
infix fun put(address: String): RequestHandler = RequestHandler(address, vertx, router, "PUT") | |
infix fun Route.with(handler: Handler<RoutingContext>): Route = this.handler(handler) | |
class RequestHandler(val address: String, val vertx: Vertx, val router: Router, val method: String) { | |
var pathMapping: Map<String, String> = mapOf() | |
var bodyMapping: Map<String, String> = mapOf() | |
var vertxAddress: String = "" | |
infix fun from(address: String): RequestHandler = this.also { vertxAddress = address; listen()} | |
infix fun to(address: String): RequestHandler = this.also { vertxAddress = address; listen()} | |
infix fun pathParams(params: Map<String, String>): RequestHandler = this.also { pathMapping = params } | |
infix fun bodyMapping(params: Map<String, String>): RequestHandler = this.also { bodyMapping = params } | |
fun listen() { | |
when (method) { | |
"GET" -> getListen() | |
"POST" -> postListen() | |
"PATCH" -> patchListen() | |
"PUT" -> putListen() | |
} | |
} | |
fun setupParams(ctx: RoutingContext): Map<String, Any> = | |
mutableMapOf<String, Any>().also { | |
ctx.pathParams().keys.filter { k -> k !in pathMapping.keys }.forEach { e -> it.put(e, ctx.pathParam(e))} | |
pathMapping.entries.forEach { e -> | |
val v = ctx.pathParam(e.key) | |
if (v != null) it.put(e.value, v) | |
} | |
ctx.bodyAsJson?.map?.run { | |
this.keys.filter { k -> k !in bodyMapping.keys }.forEach { e -> it.put(e, this.get(e)!!)} | |
bodyMapping.entries.forEach { e -> | |
val v = get(e.key) | |
if (v != null) {it.put(e.value, v)} | |
} | |
} | |
} | |
val handleResult = { ctx: RoutingContext, mm: AsyncResult<Message<JsonObject>> -> | |
ctx.response().run { | |
when (mm.failed()) { | |
true -> { | |
val cause = mm.cause() | |
when (cause) { | |
is ReplyException -> setStatusCode(cause.failureCode()).setStatusMessage(cause.message).end() | |
else -> setStatusCode(500).setStatusMessage(mm.cause().message).end() | |
} | |
} | |
else -> { | |
putHeader("Content-Type", "application/json") | |
setStatusCode(200) | |
val body = mm.result().body() | |
when { | |
body.size() == 1 && body.containsKey("values") -> end(body.getJsonArray("values").toBuffer()) | |
body.size() == 1 && body.containsKey("valueMap") -> end(body.getJsonObject("valueMap").toBuffer()) | |
else -> end(body.toBuffer()) | |
} | |
} | |
} | |
} | |
} | |
private fun getListen() { | |
println("Listening to ${address} diverted to ${vertxAddress} method ${method}") | |
router.route(address).method(HttpMethod.valueOf(method)).handler { ctx -> | |
vertx.send(vertxAddress, setupParams(ctx)) { mm -> handleResult(ctx, mm)} | |
} | |
} | |
private fun postListen() { | |
println("Listening to ${address} diverted to ${vertxAddress} method ${method}") | |
router.route().handler(BodyHandler.create()).method(HttpMethod.POST).path(address).handler { ctx -> | |
vertx.send(vertxAddress, setupParams(ctx)) { mm -> handleResult(ctx, mm)} | |
} | |
} | |
private fun patchListen() { | |
println("Listening to ${address} diverted to ${vertxAddress} method ${method}") | |
router.route().handler(BodyHandler.create()).method(HttpMethod.PATCH).path(address).handler { ctx -> | |
vertx.send(vertxAddress, setupParams(ctx)) { mm -> handleResult(ctx, mm)} | |
} | |
} | |
private fun putListen() { | |
println("Listening to ${address} diverted to ${vertxAddress} method ${method}") | |
router.route().handler(BodyHandler.create()).method(HttpMethod.PUT).path(address).handler { ctx -> | |
vertx.send(vertxAddress, setupParams(ctx)) { mm -> handleResult(ctx, mm)} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
RegisterHttpRoutes.kt is a helper Kotlin class that makes your Vert.x routing look nice.
What it does is the following:
HTTP request -[JSON Body, path params]> transformation -[JSON]> VertX Event Bus Listener -[JSON]> HTTP response
The transformation makes a JsonObject from the sent parameters (body, path) from the HTTP call.
The transformation is first off a copy of the sent params, but then also the keys can also be copied as new key/value pairs
in the path and body params mapping.
This computed map is then the parameter for the event bus listener later on. When the computation is done the listener returns
a JSON object (which is returned to the client).