Javalin is a very lightweight web framework for Kotlin and Java which supports WebSockets, HTTP2 and async requests. Javalin’s main goals are simplicity, a great developer experience, and first class interoperability between Kotlin and Java.
Javalin is more of a library than a framework. Some key points:
- You don't need to extend anything
- There are no @Annotations
- There is no reflection
- There is no other magic; just code.
General information
- The project webpage is javalin.io (the source is at javalin/javalin.github.io).
- Read the documentation on: javalin.io/documentation
- A summary of the license can be found at TLDR Legal
- Interesting issues
Community
We have a very active Discord server where you can get help quickly. We also have a (much less active) Slack if you prefer that.
Contributions are very welcome, you can read more about contributing in our guide: CONTRIBUTING
Please consider ❤️ Sponsoring or starring Javalin if you want to support the project.
Quickstart
Add dependency
Maven
<dependency>
<groupId>io.javalin</groupId>
<artifactId>javalin</artifactId>
<version>5.6.3</version>
</dependency>
Gradle
implementation("io.javalin:javalin:5.6.3")
Start programming (Java)
import io.javalin.Javalin;
public class HelloWorld {
public static void main(String[] args) {
Javalin app = Javalin.create().start(7000);
app.get("/", ctx -> ctx.result("Hello World"));
}
}
Start programming (Kotlin)
import io.javalin.Javalin
fun main() {
val app = Javalin.create().start(7000)
app.get("/") { ctx -> ctx.result("Hello World") }
}
Examples
This section contains a few examples, mostly just extracted from the docs. All examples are in Kotlin, but you can find them in Java in the documentation (it's just syntax changes).
You can find more examples in the javalin-samples repository.
Api structure and server config
val app = Javalin.create { config ->
config.http.defaultContentType = "application/json"
config.http.generateEtags = true
config.staticFiles.add("/public")
config.asyncRequestTimeout = 10_000L
config.compression.brotliAndGzip()
config.routing.caseInsensitiveRoutes = true
}.routes {
path("users") {
get(UserController::getAll)
post(UserController::create)
path("{user-id}") {
get(UserController::getOne)
patch(UserController::update)
delete(UserController::delete)
}
ws("events", userController::webSocketEvents)
}
}.start(port)
WebSockets
app.ws("/websocket/{path}") { ws ->
ws.onConnect { ctx -> println("Connected") }
ws.onMessage { ctx ->
val user = ctx.message<User>(); // convert from json string to object
ctx.send(user); // convert to json string and send back
}
ws.onClose { ctx -> println("Closed") }
ws.onError { ctx -> println("Errored") }
}
Filters and Mappers
app.before("/some-path/*") { ctx -> ... } // runs before requests to /some-path/*
app.before { ctx -> ... } // runs before all requests
app.after { ctx -> ... } // runs after all requests
app.exception(Exception.class) { e, ctx -> ... } // runs if uncaught Exception
app.error(404) { ctx -> ... } // runs if status is 404 (after all other handlers)
app.wsBefore("/some-path/*") { ws -> ... } // runs before ws events on /some-path/*
app.wsBefore { ws -> ... } // runs before all ws events
app.wsAfter { ws -> ... } // runs after all ws events
app.wsException(Exception.class) { e, ctx -> ... } // runs if uncaught Exception in ws handler
JSON-mapping
var todos = arrayOf(...)
app.get("/todos") { ctx -> // map array of Todos to json-string
ctx.json(todos)
}
app.put("/todos") { ctx -> // map request-body (json) to array of Todos
todos = ctx.body<Array<Todo>>()
ctx.status(204)
}
File uploads
app.post("/upload") { ctx ->
ctx.uploadedFiles("files").forEach { uploadedFile ->
FileUtil.streamToFile(uploadedFile.content(), "upload/${uploadedFile.filename()}")
}
}
Plugins
Javalin has a plugin system that allows you to add functionality to the core library. You can find a list of plugins here.
Installing a plugin is as easy as adding a dependency to your project and registering it with Javalin:
Javalin.create { config ->
config.plugins.register(MyPlugin())
}
Some of the most popular plugins are:
OpenAPI Plugin
The Javalin OpenAPI plugin allows you to generate an OpenAPI 3.0 specification for your API at compile time.
Annotate your routes with @OpenApi
to generate the specification:
@OpenApi(
summary = "Get all users",
operationId = "getAllUsers",
tags = ["User"],
responses = [OpenApiResponse("200", [OpenApiContent(Array<User>::class)])],
path = "/users",
methods = [HttpMethod.GET]
)
fun getAll(ctx: Context) {
ctx.json(UserService.getAll())
}
Swagger UI and ReDoc UI implementations for viewing the generated specification in your browser are also available.
For more information, see the Javalin OpenAPI Wiki.
Rendering Plugin
The Javalin Rendering plugin allows you to use any template engine with Javalin.
It includes implementations for JTE, Mustache, Velocity, Pebble, Handlebars, and Thymeleaf, but you also have to add the dependency for the template engine you want to use.
ctx.render("/templateFile.ext", mapOf("firstName" to "John", "lastName" to "Doe"))
Once you have included the javalin-rendering
artifact and one of the supported template engine dependencies in your project, Context#render
should automatically render your templates. By default, the plugin will look in src/main/resources/templates
for template files.
SSL Plugin
The Javalin SSL plugin allows you to easily configure SSL for your Javalin server, supporting a variety of formats such as PEM, PKCS12, DER, P7B, and JKS.
Enabling SSL on the 443 port is as easy as:
Javalin.create { config ->
config.plugins.register(SSLPlugin {
it.pemFromPath("/path/to/cert.pem", "/path/to/key.pem")
})
}
Sponsors
- @barbarysoftware (50 USD/m)
Special thanks
- Blake Mizerany, for creating Sinatra
- Per Wendel, for creating Spark
- Christian Rasmussen, for being a great guy
- Per Kristian Kummermo, also for being a great guy