Javalin stable is ready! ( Nov 6, 2017 )

Introducing Javalin

Javalin is a very lightweight web framework for Kotlin and Java, inspired by Sparkjava and koa.js. Javalin is written in Kotlin with a few functional interfaces written in Java. This was necessary to provide an enjoyable and near identical experience for both Kotlin and Java developers.

Javalin is really more library than framework; you don’t need to extend or implement anything and there are very few “Javalin-concepts” you have to learn. Let’s look at some examples:

Hello World

Kotlin

Java fun main ( args : Array < String >) { val app = Javalin . start ( 7000 ) app . get ( "/" ) { ctx -> ctx . result ( "Hello World" ) } } public static void main ( String [] args ) { Javalin app = Javalin . start ( 7000 ); app . get ( "/" , ctx -> ctx . result ( "Hello World" )); }

API structure and server config

Kotlin

Java val app = Javalin . create (). apply { enableStaticFiles ( "/public" ) enableStandardRequestLogging () port ( port ) }. start () app . routes { path ( "users" ) { get ( UserController :: getAllUserIds ) post ( UserController :: createUser ) path ( ":user-id" ) { get ( UserController :: getUser ) patch ( UserController :: updateUser ) delete ( UserController :: deleteUser ) } } } Javalin app = Javalin . create () . enableStaticFiles ( "/public" ) . enableStandardRequestLogging () . port ( port ) . start (); app . routes (() -> { path ( "users" , () -> { get ( UserController: : getAllUserIds ); post ( UserController: : createUser ); path ( ":user-id" (() -> { get ( UserController: : getUser ); patch ( UserController: : updateUser ); delete ( UserController: : deleteUser ); }); }); });

Filters and mappers

Kotlin

Java 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 . 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)

WebSockets

Kotlin

Java app . ws ( "/websocket" ) { ws -> ws . onConnect { session -> println ( "Connected" ) } ws . onMessage { session , message -> println ( "Received: " + message ) session . remote . sendString ( "Echo: " + message ) } ws . onClose { session , statusCode , reason -> println ( "Closed" ) } ws . onError { session , throwable -> println ( "Errored" ) } } app . ws ( "/websocket" , ws -> { ws . onConnect ( session -> System . out . println ( "Connected" )); ws . onMessage (( session , message ) -> { System . out . println ( "Received: " + message ); session . getRemote (). sendString ( "Echo: " + message ); }); ws . onClose (( session , statusCode , reason ) -> System . out . println ( "Closed" )); ws . onError (( session , throwable ) -> System . out . println ( "Errored" )); });

Object mapping

Kotlin

Java 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 . bodyAsClass ( Array < Todo > :: class . java ) ctx . status ( 204 ) } Todo [] todos = ... 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 . bodyAsClass ( Todo []. class ); ctx . status ( 204 ); });

Uploads

Kotlin

Java app . post ( "/upload" ) { ctx -> ctx . uploadedFiles ( "files" ). forEach { ( contentType , content , name , extension ) -> FileUtils . copyInputStreamToFile ( content , File ( "upload/" + name )) } } app . post ( "/upload" , ctx -> { ctx . uploadedFiles ( "files" ). forEach ( file -> { copyInputStreamToFile ( file . getContent (), new File ( "upload/" + file . getName ())); }); });

Kotlin and Java interoperability

The interoperability between Kotlin and Java is very important to Javalin. When moving a Javalin project from Java to Kotlin, you shouldn’t need to learn a new way of doing things. In the above examples you can switch between Kotlin and Java and see that everything is more or less the same, except for a few parens and semicolons. To maintain this consistent API for both languages is an important goal of the project.

Main features

Lightweight - You don’t have to learn any advanced concepts to get started

Consistent API - All handlers and mappers are void and operate on the Context (ctx)

Almost identical API for both Kotlin and Java

Not opinionated - A library rather than a framework (you never have to extend anything)

Fully customizable embedded server (Jetty)

JSON-object-mapping (via Jackson)

Simple per-endpoint auth via AccessManager interface

interface Simple static file handling

Lifecycle events

CookieStore - An easy way to serialize and store objects in cookies

Template rendering (Velocity, Freemarker, Thymeleaf, Mustache)

Markdown rendering

Get involved

If you want to contribute to the project, head on over to GitHub.

No breaking changes since 0.5.0

If you’re currently using a 0.5.X version of Javalin, upgrading to 1.0.0 should not break anything.