Javalin is a web framework runs on top of Jetty, one of the most used and stable web-servers on the JVM. You can configure the Jetty server fully, so you can easily get SSL and HTTP2 and everything else that Jetty has to offer. You can use Javelin with either Java or Kotlin languages
Javalin started as a fork of the Java and Kotlin web framework Spark, but quickly
turned into a ground-up rewrite influenced by koa.js.
Both of these web frameworks are inspired by the modern micro web framework
grandfather: Sinatra, so if you’re coming from Ruby then
Javalin shouldn’t feel too unfamiliar.
Philosophy
Like Sinatra, Javalin is not aiming to be a full web framework, but rather
just a lightweight REST API library (or a micro framework, if you must). There is no concept of MVC,
but there is support for template engines, WebSockets, and static file serving for convenience.
This allows you to use Javalin for both creating your RESTful API backend, as well as serving
an index.html with static resources (in case you’re creating an SPA). This is practical
if you don’t want to deploy an apache or nginx server in addition to your Javalin service.
If you wish to use Javalin to create a more traditional website instead of a REST APIs,
there are several template engine wrappers available for a quick and easy setup.
API design
All the methods on the Javalin instance return this, making the API fully fluent.
This will let you create a declarative and predictive REST API,
that will be very easy to reason about for new developers joining your project.
Java and Kotlin interoperability
Javalin is both a Kotlin web framework and a Java web framework, meaning the API is
being developed with focus on great interoperability between the two languages.
The library itself is written primarily in Kotlin, but has a few
core classes written in Java to achieve the best interoperability between the two languages.
Javalin is intended as a “foot in the door” to Kotlin development for companies
that already write a lot of Java.
When moving a Javalin project from Java to Kotlin, you shouldn’t need to learn a new way of doing things.
To maintain this consistent API for both languages is an important goal of the project.
Sailient features of Javalin
Simple
Unlike other Java and Kotlin web frameworks, Javalin has very few concepts that you need to learn. You never have to extend a class and you rarely have to implement an interface.
Lightweight
Javalin is just a few thousand lines of code on top of Jetty, which means its performance is almost equivalent to pure Jetty. It also means it’s very easy to reason about the source code.
Active
A new version of Javalin has been released twice a month (on average) since the first version. Don’t worry though, every version is backwards compatible. PRs and issues are reviewed swiftly, normally every week.
Interoperable
Other Java and Kotlin web frameworks usually offer separate version for each language. Javalin is being developed with interoperability in mind, so apps are built the same way in both Java and Kotlin.
Flexible
Javalin is designed to be simple and blocking, as this is the easiest programming model to reason about. However, if you set a Future as a result, Javalin switches into asynchronous mode.
Why should I use Javelin over Spring Boot or Vert.x?
Javalin is a microservice framework with a built in app server ( making it easy to produce fat jars). Unlike Vert.x this has a simple programming model and is easier to code, debug and maintain.
Spring Boot is “heavy” framework and typically requires a lot of setup for simple API app. The binaries produced are also fatter.
Javalin helps you write API based applications easily with minimal overhead and gets the job done. You also have full access to the power of JVM threading and asynchronous calls. It is, of course, possible to use all existing Java libraries, thus making Javalin an easy fit in your standard Java development ecosystem.
Can I write asynchronous code with Javalin?
Yes you can. Just set a CompletableFuture<String> or CompletableFuture<InputStream> as your result:
How “Fast” is Javelin?
This really depends on your application. Javelin apps will be “as fast” as a standard Java application
How easy is Javelin to Learn?
Javalin is a micro-framework which really does not require any additional knowledge if you are already an existing Java developer who has developed a web app before. Please note that this is not an introductory book and there are several excellent online resources and books available which teach Java and Java Web Programming basics. It is recommended to familiarize oneself with these concepts before proceeding.
Summary
Javalin is a fascinating micro-framework. I really see it as a sort of NodeJS of the JVM. Something that is needed with the abundance of opinionated and heavy-weight frameworks out there.
Chapter Two : “Hello Javelin”
Setting up your IDE
Provide instructions and a screenshot to download IntelliJ Idea.
Creating a project
IntelliJ IDEA lets you create a Maven project or add a Maven support to any existing project.
Launch the New Project wizard. If no project is currently opened in IntelliJ IDEA, click Create New Project on the Welcome screen: Otherwise, select File | New | Project from the main menu.
Select Maven from the options on the left.
Specify project’s SDK (JDK) or use a default one and an archetype if you want to use a predefined project template (configure your own archetype by clicking Add Archetype).
Click Next.
On the next page of the wizard, specify the following Maven basic elements that are added to the pom.xml file:
GroupId - a package of a new project.
ArtifactId - a name of your project.
Version - a version of a new project. By default, this field is specified automatically.
Click Next.
If you are creating a project using a Maven archetype, IntelliJ IDEA displays Maven settings that you can use to set the Maven home directory and Maven repositories. Also, you can check the archetype properties. Click Next.
Specify the name and location settings. Click Finish.
Setting up Maven
You should have the following code in your pom.xml:
TIP: To download source code of Javalin:
mvn dependency:sources
A simple “Hello Javelin” app
Create a class called HelloWorld and write the following code in it:
A quick overview of the “Hello Javelin” App
Let us now go through the application describing what each component
does in detail.
The code above starts the application on port 7000.
Let us see what internally happens when we start a Javalin app.
Javalin app internals: Startup
Javalin app internals:
The second line of the Javalin app reads:
The Context instance.
The ctx represents an instance of the Context object, which contains everything you need to handle an http request.
It contains the underlying servlet-request and servlet-response, and a bunch of getters and setters. The getters operate mostly on the request-object, while the setters operate exclusively on the response object.
Context methods: A reference
Server Startup and Lifecyle management
To start and stop the server, use the appropriately named start() and stop() methods.
Server setup: Available configurations
Custom Server
Custom jetty handlers
You can configure your embedded jetty-server with a handler-chain, and Javalin will attach it’s own handlers to the end of this chain.
Implementing a custom server with SSL
Implementing a custom server with SSL enabled is easy in Javalin, but not straightforward. It may require hunting around in the documentation. For your reference, here is a complete working example with SSL
Implementing a custom server with HTTP/2
The following is a sample server implemented with HTTP2. There is no straight-forward example easily, please use the following code below:
Note that you will have to generate a keystore locally using: keytool -genkey -alias mydomain -keyalg RSA -keystore keystore.jks -keysize 2048
Context Extensions:
Context extensions give Java developers a way of extending the Context object.
One of the most popular features of Kotlin is extension functions. When working with an object you don’t own in Java, you often end up making MyUtil.action(object, ...). If you, for example, want to serialize an object and set it as the result on the Context, you might do:
With context extensions you can add custom extensions on the context:
Context extensions have to be added before you can use them, this would typically be done in the first before filter of your app:
AccessManager for Authentication and Authorization
Javalin has a functional interface AccessManager, which let’s you set per-endpoint authentication and/or authorization. It’s common to use before-handlers for this, but per-endpoint security handlers give you much more explicit and readable code. You can implement your access-manager however you want, but here is an example implementation:
Exception Mapping
All handlers (before, endpoint, after) can throw Exception (and any subclass of Exception) The app.exception() method gives you a way of handling these exceptions:
Javalin has a HaltException which is handled before other exceptions. It can be used to short-circuit the request-lifecycle. If you throw a HaltException in a before-handler, no endpoint-handler will fire. When throwing a HaltException you can include a status code, a message, or both:
Error Mapping
Error mapping is similar to exception mapping, but it operates on HTTP status codes instead of Exceptions:
It can make sense to use them together:
WebSockets
Javalin has a very intuitive way of handling WebSockets, similar to most node frameworks:
The WsSession object wraps Jetty’s Session and adds the following methods:
Lifecycle events
Javalin has five lifecycle events: SERVER_STARTING, SERVER_STARTED, SERVER_START_FAILED, SERVER_STOPPING and SERVER_STOPPED. The snippet below shows all of them in action:
Adding a logger:
If you’re reading this, you’ve probably seen the following message while running Javalin:
Asynchronous requests
Javalin 1.6.0 introduced future results. While the default threadpool (200 threads) is enough for most use cases, sometimes slow operations should be run asynchronously. Luckily it’s very easy in Javalin, just pass a CompletableFuture to ctx.result():
You can only set future results in endpoint handlers (get/post/put/etc).
After-handlers, exception-handlers and error-handlers run like you’d expect them to after the future has been resolved or rejected.
Configuring JSON Mapper and Jackson
The JSON mapper can be configured like this:
Configuring Jackson
The JSON mapper uses Jackson by default, which can be configured by calling:
Note that these are global settings, and can’t be configured per instance of Javalin.
Views and Templates
Javalin currently supports five template engines, as well as markdown:
Configure:
Note that these are global settings, and can’t be configured per instance of Javalin.
Chapter Three: Creating a Google Docs clone with WebSockets using Javalin
What You Will Learn
In this tutorial we will create a very simple realtime collaboration tool (like google docs).
We will be using WebSockets for this, as WebSockets provides us with two-way communication over a one connection, meaning we won’t have to make additional HTTP requests to send and receive messages. A WebSocket connection stays open, greatly reducing latency (and complexity).
Dependencies
Create a maven project with dependencies
We will be using Javalin for our web-server and WebSockets, and slf4j for logging:
The Java application
The Java application is pretty straightforward. We need:
a data class (Collab) containing the document and the collaborators
a map to keep track of document-ids and Collabs
websocket handlers for connect/message/close
We can get the entire server done in about 40 lines:
We also need to create a data object for holding our document and the people working on it:
Building a JavaScript Client
In order to demonstrate that our application works, we can build a JavaScript client. We’ll keep the HTML very simple, we just need a heading and a text area:
The JavaScript part could also be very simple, but we want some slightly advanced features:
When you open the page, the app should either connect to an existing document or generate a new document with a random id
When a WebSocket connection is closed, it should immediately be reestablished
When new text is received, the user caret (“text-cursor”) should remain in the same location (easily the most complicated part of the tutorial).
And that’s it! Now try opening localhost:7070 in a couple of different browser windows (that you can see simultaneously) and collaborate with yourself.
Conclusion
We have a working realtime collaboration app written in less than 100 lines of Java and JavaScript. It’s very basic though, some things to add could include:
Show who is currently editing the document
Persist the data in a database at periodic intervals
Replace the textarea with a rich text editor, such as quill
Replace the textarea with a code editor such as ace for collaborative programming
Improving the collaborative aspects with operational transformation
The use cases are not limited to text and documents though, you should use WebSockets for any project which requires a lot of interactions with low latency. Have fun!
Chapter Four: Creating a simple chat-app with WebSockets
Aim
In this tutorial we will create a simple real-time chat application. It will feature a chat-panel that stores messages received after you join, a list of currently connected users, and an input field to send messages from. We will be using WebSockets for this, as WebSockets provides us with full-duplex communication channels over a single TCP connection, meaning we won’t have to make additional HTTP requests to send and receive messages. A WebSocket connection stays open, greatly reducing latency (and complexity).
Dependencies
First, we need to create a Maven project with some dependencies: (→ Tutorial)
The Java application
The Java application is pretty straightforward. We need:
a map to keep track of session/username pairs.
a counter for number of users (nicknames are auto-incremented)
websocket handlers for connect/message/close
a method for broadcasting a message to all users
a method for creating the message in HTML (or JSON if you prefer)
Building a JavaScript Client
In order to demonstrate that our application works, we can build a JavaScript client. First we create our index.html:
As you can see, we reference a stylesheet called style.css, which can be found on GitHub.
The final step needed for completing our chat application is creating websocketDemo.js:
And that’s it! Now try opening localhost:7070 in a couple of different browser windows (that you can see simultaneously) and talk to yourself.
Conclusion
Well, that was easy! We have a working real-time chat application implemented without polling, written in a total of less than 100 lines of Java and JavaScript. The implementation is very basic though, and we should at least split up the sending of the userlist and the messages (so that we don’t rebuild the user list every time anyone sends a message), but since the focus of this tutorial was supposed to be on WebSockets, I chose to do the implementation as minimal as I could be comfortable with.
Chapter Five: Working with HTML forms and a Java backend
Dependencies
First, we need to create a project with these dependencies: (→ Tutorial)
Setting up the backend
Create a Java file, for example Main.java, that has the following code:
This will create an app which listens on port 7777, and looks for static files in your /src/resources/public folder. We have two endpoints mapped, one post, which will make a reservation, and one get, which will check your reservation.
Settings up the HTML forms
Now we have to make two HTML forms for interacting with these endpoints. We can put these forms in a file /resources/public/index.html, which will be available at http://localhost:7777/.
Make reservation form
To make a reservation we need to create something on the server (in this case it’s a simple map.put(), but usually you’d have a database). When creating something on the server, you should use the POST method, which can be specified by adding method=”post” to the <form> element.
In our Java code, we have a post endpoint: app.post(“/make-reservation”, ctx -> {…}. We need to tell our form to use this endpoint with the action attribute: action=”/make-reservation”. Actions are relative, so when you click submit, the browser will create a POST request to http://localhost:7777/make-reservation with the day/time values as the request-body.
Check reservation form
To check a reservation we need to tell the server which day we’re interested in. In this case we’re not creating anything, and our action does not change the state of the server in any way, which makes it a good candidate for a GET request.
GET requests don’t have a request-body so when you click submit the browser creates a GET request to http://localhost:7777/check-reservation?day=saturday. The values of the form are added to the URL as query-parameters.
HTML form GET vs POST summary
POST requests should be used if the request can change the server state.
POST requests have their information stored in the request-body. In order to extract information from this body you have to use ctx.formParam(key) in Javalin.
Performing a series of GET requests should always return the same result (if no other POST request was performed in-between).
GET requests have no request-body, and form information is sent as query-parameters in the URL. In order to extract information from this body you have to use ctx.queryParam(key) in Javalin.
File upload example
Let’s expand our example a bit to include file uploads. We need to add a new dependency, a new endpoint, and a new form.
Dependency
We need to add a dependency for handling file-uploads:
Endpoint
ctx.uploadedFiles(“files”) gives us a list of files matching the name files. We then save these files to an upload folder.
HTML form
When uploading files you need to add enctype=”multipart/form-data” to your <form>. If you want to upload multiple files, add the multiple attribute to your <input>.
Chapter Six: A comparison with Spark
<h1 class=”no-margin-top”>SparkJava and Javalin comparison</h1>
People often ask about the differences between Spark and Javalin. This page shows some of them.
It’s not intended to tell you which library is better, just to highlight the differences.
Handlers vs Routes and Filters
Javalin has the concept of a Handler. A Handler is void and takes a Context (which wraps HttpServletRequest and HttpServletResponse),
and you operate on both the request and response through this Context.
Spark on the other hand has Routes and Filters. Both Route and Filter in Spark take
(Request, Response) as input. Route has a return value (Object), while Filter is void.
Request and Response wrap HttpServletRequest and HttpServletResponse, respectively.
Some other differences:
Spark can run on an application server. Javalin can only run on the included embedded Jetty server.
Javalin supports a lot of configuration options (HTTP2, Jetty Handler chains, fully customizable Jetty Server, CORS, default values). Spark has sane defaults, but limited configuration options.
Spark has a static API and an instance API. Javalin only has an instance API.
Javalin focuses on Java/Kotlin interoperability and behaves the same in both languages. Spark has Kotlin DSL (spark-kotlin) built on top of itself with “Kotlin only” features.
Spark supports route mapping based on accepts/content type. Javalin doesn’t.
Javalin supports regex routes. Spark doesn’t.
Javalin has a lambda based WebSocket API which supports path-params (and other things). Spark uses an annotation based API which proxies directly to Jetty.
Spark has a redirect DSL redirect.get("/fromPath", "/toPath");. Javalin doesn’t.
Javalin has async support for long running tasks via CompletableFuture. Spark doesn’t.
Set up the Javalin Hello World example with Maven (→ Tutorial)
Configuring Maven
This is actually where most of the work is done. In order to easily
deploy a Java application anywhere, you have to create a jar file
containing your application and all of its dependencies.
Open the pom.xml of your Javalin Maven project and add the
following configuration (below your dependencies tag):
Configuring Docker
Before we can configure anything we must create a Dockerfile.
We can create a text file using any editor and name it Dockerfile.
Copy below contents to the Dockerfile and move this file to root of your project.
When you’ve added the Dockerfile to your project,
it should look like this
To build a docker image for your application we will use dockerfile-maven-plugin
(dockerfile-maven-plugin).
Set DOCKER_HOST environment variable as mentioned (here).
In the repository section “localhost:5000” is the registry url.
When you’ve added the Docker config to your pom,
it should look like this
Making Javalin Listen on the Correct Port
The only thing left is making sure Javalin can handle your requests.
We have exposed port 7000 in Dockerfile. That means that 7000 port on the container is accessible to the outside world.
So we will configure Javalin to listen on “7000”
## Build and Push Docker image
Now we can deploy our application using mvn deploy.
This will build the docker image and push it to your registry server.
Image name is same as repository value in the pom.
Additionally we add a tag to image to specify images for different versions.
So image name for this example is localhost:5000/javalin:1.0.0-SNAPSHOT.
Again, make sure you’re in your project root, then enter:
Run Docker image
Now we can run our application using docker run.
open terminal then enter:
That’s it. Our application is now available at http://localhost:7000/
Chapter 8: Sending email with Javalin
Dependencies
First, we need to create a Maven project with some dependencies: (→ Tutorial)
Setting up the backend
We need three endpoints: GET '/', POST '/contact-us' and GET '/contact-us/success':
Before we can configure anything, we actually have to create a
Heroku application. This can be done by using the heroku create command.
Open a terminal and navigate to your project root, then enter:
Now that you have a Heroku application, we have to configure how to
deploy it using Maven. This is pretty straightforward using the Heroku Maven plugin.
We specify the JDK version and the app-name, along with the launch config:
When you’ve added the Heroku config to your pom,
it should look like this
Making Javalin Listen on the Correct Port
The only thing left is making sure Javalin can handle your requests.
Heroku assigns your application a new port every time you deploy it,
so we have to get this port and tell Javalin to use it:
Now we can deploy our application using mvn heroku:deploy.
Again, make sure you’re in your project root, then enter:
That’s it. Our application is now available at https://<appname>.herokuapp.com/
Chapter 10: Authentication with Javalin
Dependencies
First, create a new Gradle project with the following dependencies: (→ Tutorial)
## Creating controllers
We need something worth protecting.
Let’s pretend we have a very important API for manipulating a user database.
We make a controller-object with some dummy data and CRUD operations:
We’re using !! to convert nullables to non-nullables.
If :user-id is missing or users[id] returns null, we’ll get a NullPointerException
and our application will crash. Handling this is outside the scope of the tutorial.
Creating roles
Now that we have our functionality, we need to define a set of roles for our system.
This is done by implementing the Role interface from io.javalin.security.Role.
We’ll define three roles, one for “anyone”, one for permission to read user-data,
and one for permission to write user-data.
Setting up the API
Now that we have roles, we can implement our endpoints:
A role has now been given to every endpoint:
* ANYONE can getAllUserIds
* USER_READ can getUser
* USER_WRITE can createUser, updateUser and deleteUser
Now, all that remains is to implement the access-manager (Auth::accessManager).
Implementing auth
The AccessManager interface in Javalin is pretty simple.
It takes a Handler a Context and a list of Roles.
The idea is that you implement code to run the handler
based on what’s in the context, and what roles are set for the endpoint.
The rules for our access manager are also simple:
* When endpoint has ApiRole.ANYONE, all requests will be handled
* When endpoint has another role set and the request has matching credentials, the request will be handled
* Else we ignore the request and send 401 Unauthorized back to the client
This translates nicely into Kotlin:
Extracting user-roles from the context
There is no ctx.userRoles concept in Javalin, so we need to implement it.
First we need a user-table. We’ll create a map(Pair<String, String>, List<Role>) where keys are
username+password in cleartext (please don’t do this for a real service), and values are user-roles:
Now that we have a user-table, we need to authenticate the requests.
We do this by getting the username+password from the Basic-auth-header
and using them as keys for the userRoleMap:
When using basic auth, credentials are transferred as plain text
(although base64-encoded).
Remember to enable SSL if you’re using basic-auth for a real service.**
Conclusion
This tutorial showed one possible way of implementing an AccessManager in Javalin, but
the interface is very flexible and you can really do whatever you want:
Leanpub requires cookies in order to provide you the best experience.
Dismiss