A Netty-based web-server serving files and web-pages via the HTTP-protocol and providing an advanced routing system.
BacKT WebServer is a part of «Back-end Kotlin Tool Set» that consists of:
- BacKT SQL (a library for SQL-databases)
- BacKT WebServer (this one)
It also uses KotLog for logging.
repositories {
maven { url "http://dl.bintray.com/azadev/maven" }
}
dependencies {
compile "azadev.backt:backt_webserver:0.9.1"
}Run this code and open http://localhost/:
val server = WebServer()
server.get("/", {
response.send("Hello World!", "text/plain")
})
server.post("/do-job", {
// do some job
response.send("Done!", "text/plain")
})
server.start()Available methods:
getpostgetOrPostputheaddeleteoptionspatch
Each method receives:
- Pattern –
Stringpattern orRouteinstance; - Interceptor – either a lambda returning
Boolean, or an instance ofAInterceptor; - (optional) Position of the callback in the execution flow –
InterceptOnenum.
BacKT WebServer provides an advanced routing system, which allows to filter requests using sophisticated patterns and wildcards.
| PATTERN | WILL MATCH | WON'T MATCH |
|---|---|---|
| * | (anthing) | (nothing) |
| / | / | /user |
| /user | /user | / /user234 /user/john |
| /user/:name | /user/john | /user /user/john/status |
| /user/#id | /user/234 | /user /user/john |
| /user#id/:action | /user234/info /user567/delete |
/user234 /users/list /user234/info/send |
| /user* | /user /user234/info |
/page/user234 |
| /files/*.css | /files/fonts.css /files/css/main/fonts.css |
/uploads/fonts.css |
| /*/*#id | /user/id234 | /user /id234 /user/john |
Pattern may be defined either as a plain String, or a Route instance:
// Plain String:
server.get("/blog/post#id", { ... })
// Route object:
val BLOG_POST = Route("/blog/post#id")
server.get(BLOG_POST, { ... })Route is a wrapper for URL patterns that can help you handle all the URLs within your site:
// Create a Route directly:
val BLOG = Route("/blog")
// Create a new Route based on the previous one:
val BLOG_POST = BLOG + "/post#id"
// Compile to a String:
val string = BLOG_POST(234) // will compile to: /blog/post234
// With query-params:
val string = BLOG(queryParams = mapOf("post" to 234)) // will compile to: /blog?post=234Interceptor is a kind of callback or handler that must populate the response. For example:
val server = WebServer()
server.get("/", {
response.setCookie(name = "uid", value = "123")
response.send("Hello World!", "text/plain")
})
server.get("/file.js", {
response.sendFile(file, "text/javascript")
})
server.get("/redirect-me", {
response["Location"] = url
response.status = HttpResponseStatus.FOUND
})
server.start()Interceptor may be a lambda, or an instance of AInterceptor:
class MyInterceptor : AInterceptor
{
override fun CallReferences.intercept(): Boolean {
return response.send("Hello World!")
}
}Both lambda and the intercept method are being called using a CallReferences instance as a receiver. This is a kind of a data object that holds the data needed to handle the request.
Interceptors are named thus (not, let's say, "handlers") to be more distinctive: "handler" is a very frequently used name. Netty uses it too.
Each interceptor has a position within the execution flow. The execution flow consists of 6 steps:
PRE_REQUESTPRE_EXECUTION,EXECUTIONandPOST_EXECUTIONERRORPOST_REQUEST
By default interceptors are being added to the EXECUTION step. To explicitly specify the position of an interceptor use the InterceptOn enum:
// This callback will be called first, for any page;
// If it returns "false", then *EXECUTION interceptors will be skipped:
server.get("*", { ... }, InterceptOn.PRE_REQUEST)
// This will be called only if an error happens on /blog* pages:
server.get("/blog*", { ... }, InterceptOn.ERROR)There may be many interceptors within a single step. Interceptors are being called following these rules:
- Interceptors are being called accordingly to the step they are belong to, and in the order they are added.
- If an interceptor returns
false, then next interceptors within this step won't be called. - If an interceptor of the
PRE_REQUESTstep returnsfalse, the execution flow skips all the*EXECUTIONsteps. - If an interceptor of any
*EXECUTIONstep returnsfalse, the execution flow skips all the remaining interceptors within*EXECUTIONsteps. For example, if a callback of thePRE_EXECUTIONstep returnsfalse, neitherEXECUTIONnorPOST_EXECUTIONinterceptors will be called. ERRORinterceptors will be called beforePOST_REQUESTifResponsestatus code is set to4xxor5xx.- In case an unhandled exception is caught, the status code will be set to
500and the execution flow will jump right to theERRORstep.
This software is released under the MIT License. See LICENSE.md for details.