Javalin: A Tiny but Mighty Framework

Two years ago, I wrote an article Microservices in a minute using the open source framework MSF4J. Today I came across another framework Javalin: another lightweight framework to develop lightweight web applications with less or no effort. We already have plenty of web frameworks including the shining star Spring. What makes Javalin different is its simplicity. In addition, it can be used as a microservice framework or a tiny web framework to serve a web application with static files. In Javalin developers' words:

Javalin’s main goals are simplicity, a great developer experience, and first-class interoperability between Kotlin and Java.

Comparing Javalin with Spring is like comparing a shaving blade with a Wenger 16999 Swiss Army Knife Giant, but it does what it is supposed to do. If you want to quickly add a REST endpoint for a quick demo or if you just need a simple web framework without any additional gimmicks like Dependency Injection or Object Relational Mapping, consider Javalin. It is easy to learn and lighter to run.


In this article, you will see how to use Javalin as a web framework to serve a contact-us page and how to build a CRUD micro-service using Javalin.

Requirements:

Javalin as a Web Framework

To see how easy to use Javalin, let's create a simple web application to show a "Contact Us" page. In this article, we will just print the message in the console. If you like to send an actual email, please consider using the Apache Commons Email library.

Step 1:
Create a new Maven project in IntelliJ Idea with an artifact id: com.javahelps.javalindemo and a project id: contact-us.

Step 2:
Add the javalin and the slf4j-simple dependencies to the pom.xml file as shown below. slf4j-simple dependency is used for logging purposes.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.javahelps.javalindemo</groupId>
    <artifactId>contact-us</artifactId>
    <version>1.0-SNAPSHOT</version>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>11</source>
                    <target>11</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>io.javalin</groupId>
            <artifactId>javalin</artifactId>
            <version>2.7.0</version>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>1.7.25</version>
        </dependency>
    </dependencies>

</project>

Step 3:
Create a new folder web in the main/resources folder.

Step 4:
Create a new file index.html in the web folder with the following code. This HTML file creates a form with first name, last name, subject and message fields. The Submit button click will send a POST request to the contact-us URL.
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Contact Us</title>
    <style>
        body {
            font-family: Arial, Helvetica, sans-serif;
        }

        * {
            box-sizing: border-box;
        }

        input[type=text], select, textarea {
            width: 100%;
            padding: 12px;
            border: 1px solid #ccc;
            border-radius: 4px;
            box-sizing: border-box;
            margin-top: 6px;
            margin-bottom: 16px;
            resize: vertical;
        }

        input[type=submit] {
            background-color: #4CAF50;
            color: white;
            padding: 12px 20px;
            border: none;
            border-radius: 4px;
            cursor: pointer;
        }

        input[type=submit]:hover {
            background-color: #45a049;
        }

        .container {
            border-radius: 5px;
            background-color: #f2f2f2;
            padding: 20px;
        }
    </style>
</head>
<body>
<div class="container">
    <form action="contact-us" method="post">

        <label for="firstName">First Name</label>
        <input type="text" id="firstName" name="firstName" placeholder="Your name...">

        <label for="lastName">Last Name</label>
        <input type="text" id="lastName" name="lastName" placeholder="Your last name...">

        <label for="subject">Subject</label>
        <input type="text" id="subject" name="subject" placeholder="Subject...">

        <label for="message">Message</label>
        <textarea id="message" name="message" placeholder="Write something..." style="height:200px"></textarea>

        <input type="submit" value="Submit">

    </form>
</div>
</body>
</html>

Step 5:
Create another file success.html under the same folder with the following code. This file is later used in the application to show a thank you message to the user.
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Thank You</title>

    <style>
        body {
            font-family: Arial, Helvetica, sans-serif;
            text-align: center;
        }

        * {
            box-sizing: border-box;
        }

        h1 {
            width: 100%;
            vertical-align: center;
            horiz-align: center;
            margin-top: 120px;
            resize: vertical;
        }
    </style>
</head>
<body>
<h1>Thank you for contacting us – we will get back to you soon!</h1>
</body>
</html>

Step 6:
Create a new package com.javahelps.javalindemo.contactus in the src/main/java folder.

Step 7:
Create a new class named Main inside that package with the following code.
package com.javahelps.javalindemo.contactus;

import io.javalin.Javalin;

public class Main {

    public static void main(String[] args) {
        Javalin app = Javalin.create()
                .port(8080)
                .enableStaticFiles("web")
                .start();

        app.post("/contact-us", ctx -> {
            String fullName = ctx.formParam("firstName") + " " + ctx.formParam("lastName");
            String subject = ctx.formParam("subject");
            String message = ctx.formParam("message");
            System.out.println("Message received from " + fullName);
            System.out.println("Subject: " + subject);
            System.out.println(message);
            ctx.redirect("/success.html");
        });
    }
}

The above class creates a Javalin application, set the port to be 8080, serve static files from the web folder which is in the classpath and define a post endpoint to receive the form action. After handling the post action, we redirect the user to the success.html page.

Running this code will start a Jetty server on port 8080. Visiting http://localhost:8080/ will show you the index.html page. The submitted message will be printed to the console according to our implementation.


Even though we used Javalin to develop a simple full-stack application, nothing prevents you from using Javalin as a micro-service framework. In the following section, you will learn how to create a simple micro-service using Javalin.


Javalin as a Microservice Framework

Step 1:
Create another Maven project in IntelliJ Idea with an artifact id: com.javahelps.javalindemo and a project id: student-crud.

Step 2:
Add the javalin, jackson and slf4j-simple dependencies to the pom.xml file as shown below. jackson is used to map requests and responses to and from Plain Old Java Objects (POJOs). slf4j-simple dependency is used for logging purposes.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.javahelps.javalindemo</groupId>
    <artifactId>contact-us</artifactId>
    <version>1.0-SNAPSHOT</version>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>11</source>
                    <target>11</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>io.javalin</groupId>
            <artifactId>javalin</artifactId>
            <version>2.7.0</version>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.8</version>
        </dependency>
    </dependencies>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>1.7.25</version>
        </dependency>
    </dependencies>

</project>

Step 3:
Create a new package com.javahelps.javalindemo.studentcrud in the src/main/java folder.

Step 4:
Create a new class Student with the following code. Make sure to create getter setter methods for all fields.
package com.javahelps.javalindemo.studentcrud;

import java.util.Objects;

public class Student {

    private String id;
    private String name;
    private int age;

    public Student() {

    }

    public Student(String id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return Objects.equals(id, student.id);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id);
    }

    @Override
    public String toString() {
        return "Student{" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

Step 5:
Create a new class StudentController inside that package with the following code. Student controller uses a HashMap to simulate a database. The code is pretty self-explanatory. As you can see it provides the basic CRUD operations.
package com.javahelps.javalindemo.studentcrud;

import io.javalin.Context;
import io.javalin.apibuilder.CrudHandler;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;

public class StudentController implements CrudHandler {

    private static final Logger LOGGER = LoggerFactory.getLogger(StudentController.class);

    private Map<String, Student> students = new HashMap<>();

    public void create(@NotNull Context context) {
        Student student = context.bodyAsClass(Student.class);
        LOGGER.info("Create a new student {}", student);
        this.students.put(student.getId(), student);
    }

    public void delete(@NotNull Context context, @NotNull String resourceId) {
        LOGGER.info("Delete the student {}", resourceId);
        this.students.remove(resourceId);
    }

    public void getAll(@NotNull Context context) {
        LOGGER.info("Get all students");
        context.json(students.values());
    }

    public void getOne(@NotNull Context context, @NotNull String resourceId) {
        LOGGER.info("Get the student {}", resourceId);
        Student student = this.students.get(resourceId);
        if (student != null) {
            context.json(student);
        }
    }

    public void update(@NotNull Context context, @NotNull String resourceId) {
        LOGGER.info("Update the student {}", resourceId);
        Student student = context.bodyAsClass(Student.class);
        this.students.put(resourceId, student);
    }
}

Step 6:
Create another class Main with the following code. The StudentController is mapped to /students/:student-id URL. Javalin takes care of mapping URLs to the relevant methods.
package com.javahelps.javalindemo.studentcrud;

import io.javalin.Javalin;

import static io.javalin.apibuilder.ApiBuilder.crud;

public class Main {

    public static void main(String[] args) {

        Javalin app = Javalin.create()
                .enableCorsForAllOrigins()
                .start(8080);

        app.routes(() -> crud("/students/:student-id", new StudentController()));
    }
}

Running this code will start the web-service on localhost:8080 with the following REST endpoints.
HTTP Method URL Input Description
POST http://localhost:8080/students application/json
{
 "id": "s0001",
 "name": "Alice",
 "age": 12
}
Create a new student
GET http://localhost:8080/students N/A Read all users
GET http://localhost:8080/students/s0001 Path parameter (Note the URL ending with s0001) Read the user with id 's0001'
PATCH http://localhost:8080/students/s0001 Path parameter (Note the URL ending with s0001)
application/json
{
 "id": "s0001",
 "name": "Bob",
 "age": 12
}
Update the student with id 's0001'
DELETE http://localhost:8080/students/s0001 Path parameter (Note the URL ending with s0001) Delete the student with id 's0001'

Though Javalin is simple and lightweight, it also offers a rich set of features (though it is nothing compared to Spring Javalin comes with all basic features for a simple web application). For more details, please visit the official Javalin website: javalin.io

In a nutshell, if you hate the bloated dependencies come with Spring for your project or if you want to develop a quick demo without spending a lot of time in learning a framework consider Javalin.
If you have any questions regarding Javalin, feel free to comment below.





Previous
Next Post »

Contact Form

Name

Email *

Message *