Rapidoid - Extremely Fast, Simple and Powerful Java Web Framework!

Rapidoid consists of several modules which can be used separately or together:
Add rapidoid-quick as Maven dependency:
<dependency>
    <groupId>org.rapidoid</groupId>
    <artifactId>rapidoid-quick</artifactId>
    <version>5.2.8</version>
</dependency>
Full documentation with all examples

Running this single line of code will start a web server embedded in your application.

By default, the server listens on port 8888 and address 0.0.0.0 (matching any IP address).

Navigating to http://localhost:8888/size?msg=abc will return 3.

// On GET /size return the length of the "msg" parameter
On.get("/size").json((String msg) -> msg.length());
GET /size?msg=abc
3

HTTP server routes information:

Verb Path Zone Content type MVC View name Roles
GET /size main json
// On GET /hi or POST /hi return a "Hello World" web page
On.page("/hi").mvc("Hello <b>world</b>!");
config.yml
app:
  brand: 'Cool app!'
  title: 'the head title'
  search: true
  menu:
    Home: /
    Portfolio: /portfolio
    About:
      About Us: /about
      About You: /

Let's send some HTTP requests and check the results:

GET /hi
Hello world!

HTTP server routes information:

Verb Path Zone Content type MVC View name Roles
GET POST /hi main html hi
On.address("127.0.0.1").port(9999);
 
On.get("/x").json("x"); // continue with normal setup

A web application can be defined as a collection of HTTP request handlers. The HTTP requests are routed to the appropriate lambda, based on the combination of:

  • the request verb (GET, POST, PUT, DELETE, PATCH, OPTIONS, HEAD, TRACE)
  • and the request path (e.g. /books/123, /users, /)
// Request handlers should match both the verb and the path:
On.get("/").json("Hi!");
 
On.get("/x").html("Getting X");
 
On.post("/x").json((Req req) -> "Posting X");
 
On.delete("/x").html((Req req) -> "<b>Deleting X</b>");
GET /
"Hi!"
GET /x
Getting X
POST /x
"Posting X"
DELETE /x
Deleting X

HTTP server routes information:

Verb Path Zone Content type MVC View name Roles
GET / main json
GET /x main html
POST /x main json
DELETE /x main html
// Retrieving request info from the Req parameter
On.get("/showVerb").json((Req req) -> req.verb());
 
On.get("/showPath").json((Req req) -> req.path());
 
On.get("/showUri").json((Req req) -> req.uri());
 
On.get("/showData").json((Req req) -> req.data());
GET /showVerb
"GET"
GET /showPath
"/showPath"
GET /showUri
"/showUri"
GET /showData?x=1&y=abc
{"x":"1","y":"abc"}

HTTP server routes information:

Verb Path Zone Content type MVC View name Roles
GET /showData main json
GET /showPath main json
GET /showUri main json
GET /showVerb main json

Basic Request Info API (in interface Req):

String verb()
Gets the verb of the HTTP request.
String uri()
Gets the uri of the HTTP request.
String path()
Gets the path of the HTTP request.
String query()
Gets the query of the HTTP request.
byte[] body()
Gets the raw body data of the HTTP request.
String contextPath()
Gets the context path of the application zone handling the request.
The default context path is / for the On API, and /_ for the Admin API.
Map<String, String> params()
Gets the URL parameters of the HTTP request.
Map<String, Object> posted()
Gets the posted parameters of the HTTP request body.
Map<String, List<Upload>> files()
Gets the uploaded files from the HTTP request body.
Map<String, Object> data()
Gets the data parameters (URL parameters + posted parameters + uploaded files) of the HTTP request.
Map<String, String> headers()
Gets the headers of the HTTP request.
Map<String, String> cookies()
Gets the cookies of the HTTP request.
// Returning the request or response object means the response was constructed
On.get("/").html((Req req) -> {
    Resp resp = req.response();
    resp.contentType(MediaType.JSON);
    resp.result("hello");
    return resp;
});
GET /
"hello"

HTTP server routes information:

Verb Path Zone Content type MVC View name Roles
GET / main html

Basic Response Construction API (in interface Resp):

Resp body(byte[] body)
Sets the HTTP response body from a byte[] data that is written as a HTTP response body when rendered.
Resp body(ByteBuffer body)
Sets the HTTP response body from a ByteBuffer data that is written as a HTTP response body when rendered.
Object body()
Gets the HTTP response body data (of type byte[] or ByteBuffer) that is written as a HTTP response body when rendered.
Resp code(int code)
Sets the status code (e.g. 200, 404, 500) of the HTTP response.
int code()
Gets the status code (e.g. 200, 404, 500) of the HTTP response.
Resp contentType(MediaType contentType)
Sets the Content-Type header to be rendered in the HTTP response.
MediaType contentType()
Gets the Content-Type header to be rendered in the HTTP response.
Map<String, String> headers()
Provides read/write access to the headers of the HTTP response.
Map<String, String> cookies()
Provides read/write access to the cookies of the HTTP response.
Resp html(Object content)
Sets the Content-Type: text/html; charset=utf-8 header and the content of the HTTP response.
Alias to contentType(MediaType.HTML_UTF_8).body(content).
Resp json(Object content)
Sets the Content-Type: application/json header and the content of the HTTP response.
Alias to contentType(MediaType.JSON).body(content).
Any object can be a POJO controller.
Just annotate the request handler methods with: @GET, @POST , @PUT, @DELETE etc.
App.beans(new Object() {
 
    @GET
    public String upper(@Param("s") String s) {
        return s.toUpperCase();
    }
 
    @POST
    public String lower(Req req, Resp resp, @Param("x") String s) {
        return s.toLowerCase();
    }
 
});
GET /upper?s=abc
"ABC"
POST /lower?x=HEY
"hey"
My.errorHandler((req, resp, error) -> {
    return resp.code(200).result("Error: " + error.getMessage());
});
 
On.get("/hi").html((Req req) -> {
    throw new RuntimeException("problem!");
});
GET /hi
Error: problem!
// The handler for /msg returns the model
// The default view name is msg
// So the corresponding template is templates/msg.html
On.page("/msg").mvc(() -> {
    return U.map("count", 12, "oki", GUI.btn("OK"));
});
 
// A custom view name can be assigned.
// In this case the default view name is abc,
// but a custom view name msg was specified
On.get("/abc").view("msg").mvc((Req req, Resp resp) -> {
    return U.map("count", 100, "oki", "");
});
templates/msg.html
<p>
    You have <span class="badge">${count}</span> new messages.
</p>
 
@{oki}
GET /msg

You have 12 new messages.

GET /abc

You have 100 new messages.

HTTP server routes information:

Verb Path Zone Content type MVC View name Roles
GET /abc main html msg
GET POST /msg main html msg

MVC Helper API (in interface Resp):

Resp view(String viewName)
Sets a custom name of the view (V from MVC) of the HTTP response.
This also sets mvc to true.
The default view name equals the request path without the "/" prefix, except for the "/" path, where the view name is "index".
E.g. "/abc" -> "abc", "/" -> "index", "/my/books" -> "my/books".
String view()
Gets the (default or customized) name of the view (V from MVC) of the HTTP response.
The default view name equals the request path without the "/" prefix, except for the "/" path, where the view name is "index".
E.g. "/abc" -> "abc", "/" -> "index", "/my/books" -> "my/books".
Resp noView()
Disables the view rendering for the target MVC route. The page decorator remains enabled.
Map<String, Object> model()
Provides read/write access to the model (M from MVC) that will be rendered by the view renderer.
Resp model(String name, Object value)
Sets an attribute of the model (M from MVC) that will be rendered by the view renderer.
Main.java
import org.rapidoid.setup.On;
 
public class Main {
 
    public static void main(String[] args) {
        On.get("/").html("Home");
    }
 
}
c.html
Hello from C!
public/a.html
Hello from A!
static/b.html
Hello from B!
GET /
Home
GET /a.html
Hello from A!
GET /b.html
Hello from B!
GET /c.html
404 Not found!

HTTP server routes information:

Verb Path Zone Content type MVC View name Roles
GET / main html
Main.java
import org.rapidoid.setup.App;
import org.rapidoid.setup.My;
import org.rapidoid.setup.On;
import org.rapidoid.u.U;
 
public class Main {
 
    public static void main(String[] args) {
        App.bootstrap(args).auth();
 
        On.get("/").html((req, resp) -> "this is public!");
 
        On.get("/manage").roles("manager").html((req, resp) -> "this is private!");
 
        // Dummy login: successful if the username is the same as the password
        My.loginProvider((req, username, password) -> username.equals(password));
 
        // Gives the 'manager' role to every logged-in user
        My.rolesProvider((req, username) -> U.set("manager"));
    }
 
}
MyCtrl.java
import org.rapidoid.annotation.Controller;
import org.rapidoid.annotation.GET;
import org.rapidoid.security.Role;
import org.rapidoid.security.annotation.Administrator;
import org.rapidoid.security.annotation.Roles;
import org.rapidoid.u.U;
 
@Controller
public class MyCtrl {
 
    @GET
    @Administrator
    @Roles({"manager", Role.MODERATOR})
    public Object hi() {
        return U.map("msg", "hi!");
    }
 
}

Let's send some HTTP requests and check the results:

GET /
this is public!
GET /manage
GET /hi
{"error":"The user doesn't have the required roles!","code":403,"status":"Forbidden"}
POST /_login {"username":"foo","password":"wrong"}
{"success":false,"token":""}
POST /_login {"username":"foo","password":"foo"}
{"success":true,"token":"<PRIVATE_USER_TOKEN>"}
GET /manage
this is private!
GET /hi
{"msg":"hi!"}

HTTP server routes information:

Verb Path Zone Content type MVC View name Roles
GET / main html
POST /_login main json
GET /_logout main json logged_in
GET /hi main json
 administrator
 manager
 moderator
GET /manage main html manager

The server-side session is a simple in-memory storage in the web server. While this is not a problem when running only one web server, scaling out is non-trivial, requiring sticky sessions or replicating the session, or storing it into some datastore.

On.req(req -> {
    int counter = req.session("n", 0) + 1;
    req.session().put("n", counter);
    return counter;
});
GET /first
1
GET /second
2
GET /third
3

Server-side Session API (in interface Req):

String sessionId()
Returns the ID of the session (the value of the "JSESSIONID" cookie). If a session doesn't exist, a new session is created.
boolean hasSession()
Does the HTTP request have a server-side session attached?
Map<String, Serializable> session()
Provides read/write access to the server-side session attributes of the HTTP request/response.
T session(String name)
Returns the value of the specified server-side session attribute from the HTTP request/response, or throws a runtime exception if it is not found.
T session(String name, T defaultValue)
Returns the value of the specified server-side session attribute from the HTTP request/response, or the specified default value, if it is not found.

Server-side Session API (in interface Resp):

Map<String, Serializable> session()
Provides read/write access to the server-side session attributes of the HTTP request/response.
Resp session(String name, Serializable value)
Sets a session attribute of the HTTP response.

Token Session API (in interface Req):

boolean hasToken()
Does the HTTP request have a token attached?
Map<String, Serializable> token()
Provides read/write access to the token attributes of the HTTP request/response.
T token(String name)
Returns the value of the specified token attribute from the HTTP request/response, or throws a runtime exception if it is not found.
T token(String name, T defaultValue)
Returns the value of the specified token attribute from the HTTP request/response, or the specified default value, if it is not found.

Token Session API (in interface Resp):

Map<String, Serializable> token()
Provides read/write access to the token attributes of the HTTP request/response.
Resp token(String name, Serializable value)
Sets a token attribute of the HTTP response.

The content type of the the HTTP response is automatically set to application/json for RESTful services, and to text/html for web pages.

However, it's easy to modify it using the Resp#contentType method:

// The response type will be JSON, instead of HTML
On.get("/").html((Req req) -> {
    Resp resp = req.response();
    resp.contentType(MediaType.JSON);
    resp.result("abc");
    return resp;
});
GET /
"abc"

HTTP server routes information:

Verb Path Zone Content type MVC View name Roles
GET / main html

Response Code API (in interface Req):

MediaType contentType()
Gets the Content-Type header of the HTTP response if it has been assigned, or the default value as configured in the HTTP route.

Response Code API (in interface Resp):

Resp contentType(MediaType contentType)
Sets the Content-Type header to be rendered in the HTTP response.
MediaType contentType()
Gets the Content-Type header to be rendered in the HTTP response.

The HTTP response code is automatically set to 200 when the lambda executes successfully. In case of redirect, it is automatically set to 303. In case of error, it is automatically set to 500, or if a lambda was not found for the request, it is set to 404.

However, it's easy to modify it using the Resp#code method:

On.get("/").html((Req req) -> req.response().result("").code(404));
GET /
404 Not found!

HTTP server routes information:

Verb Path Zone Content type MVC View name Roles
GET / main html

Response Type API (in interface Resp):

Resp code(int code)
Sets the status code (e.g. 200, 404, 500) of the HTTP response.
int code()
Gets the status code (e.g. 200, 404, 500) of the HTTP response.
// A wrapper executes before the handler
On.defaults().wrappers((req, next) -> {
    return next.invokeAndTransformResult(result -> "Hey: " + result);
});
 
// and provides transformation for the result
On.get("/size").json((String s) -> s.length());
On.get("/upper").json((String s) -> s.toUpperCase());
GET /size?s=abcde
"Hey: 5"
GET /upper?s=abc
"Hey: ABC"

HTTP server routes information:

Verb Path Zone Content type MVC View name Roles
GET /size main json
GET /upper main json
// Returning a null means NOT FOUND
On.get("/").json((Req req) -> {
    return req.params().size() == 1 ? req.params() : null;
});
GET /
404 Not found!
GET /?a=1
{"a":"1"}
GET /?a=1&b=2
404 Not found!

HTTP server routes information:

Verb Path Zone Content type MVC View name Roles
GET / main json
// Generic handlers match any request (in the declaration order)
On.req(req -> req.data().isEmpty() ? "Simple: " + req.uri() : null);
 
// The next handler is executed if the previous returns NOT FOUND
On.req(req -> U.list(req.verb(), req.uri(), req.data()));
GET /foo
Simple: /foo
POST /hey?name=Rapidoid {"cool":true}
[POST, /hey?name=Rapidoid, {name=Rapidoid, cool=true}]
// Wait 1 second before returning a response
On.get("/").json((Req req) -> Jobs.schedule(() -> {
 
    req.response().result("OK").done();
 
}, 1, TimeUnit.SECONDS));
GET /
"OK"

HTTP server routes information:

Verb Path Zone Content type MVC View name Roles
GET / main json

Asynchronous Processing API (in interface Req):

Req async()
Informs the HTTP server that the request will be handled asynchronously (typically on another thread). When the response is complete, the Req#done() or Resp#done() method must be called, to inform the server.
boolean isAsync()
Is/was the request being handled in asynchronous mode?
Req done()
Informs the HTTP server that the asynchronous handling has finished and the response is complete.
boolean isDone()
Has the request handling and response construction finished?

Asynchronous Processing API (in interface Resp):

Resp done()
Informs the HTTP server that the asynchronous handling has finished and the response is complete.
Alias to request().done().
Main.java
import org.rapidoid.setup.App;
 
public class Main {
 
    public static void main(String[] args) {
        App.bootstrap(args);
    }
 
}
SubUrlParams.java
@Controller
public class SubUrlParams {
 
    @GET("/hey/{name}/{age:\\d+}")
    public String hey(String name, int age) {
        return U.frmt("Hey %s (%s)", name, age);
    }
 
    @POST("/size/{s}")
    public int size(String s) {
        return s.length();
    }
 
}
GET /hey/Joe/50
"Hey Joe (50)"
GET /hey/You!/123
"Hey You! (123)"
POST /size/abc
3

HTTP server routes information:

Verb Path Zone Content type MVC View name Roles
GET /hey/{name}/{age:\d+} main json
POST /size/{s} main json
Main.java
import org.rapidoid.setup.App;
 
public class Main {
 
    public static void main(String[] args) {
        App.bootstrap(args);
    }
 
}
TextTools.java
@Controller
public class TextTools {
 
    @GET("/upper/{s}")
    public Map<String, String> upper(String s) {
        String big = s.toUpperCase();
        return U.map("normal", s, "big", big);
    }
 
    @POST
    public String[] parts(String text) {
        return text.split("-");
    }
 
}
GET /upper/abc
{"normal":"abc","big":"ABC"}
POST /parts {"text":"just-some-words"}
["just","some","words"]

HTTP server routes information:

Verb Path Zone Content type MVC View name Roles
POST /parts main json
GET /upper/{s} main json
Main.java
import org.rapidoid.setup.App;
 
public class Main {
 
    public static void main(String[] args) {
        App.bootstrap(args);
    }
 
}
Book.java
public class Book {
 
    public String title = "Untitled";
 
    private int year;
 
    public int getYear() {
        return year;
    }
 
    public void setYear(int year) {
        this.year = year;
    }
}
EasyBeans.java
@Controller
public class EasyBeans {
 
    @GET
    public Book echo(Book book) {
        return book;
    }
 
}
GET /echo?year=2012&title=Abc
{"title":"Abc","year":2012}
GET /echo?year=2015
{"title":"Untitled","year":2015}

HTTP server routes information:

Verb Path Zone Content type MVC View name Roles
GET /echo main json
Main.java
import org.rapidoid.setup.App;
 
public class Main {
 
    public static void main(String[] args) {
        App.bootstrap(args);
    }
 
}
NamedParams.java
@Controller
public class NamedParams {
 
    @GET
    public int sum(int x, @Param("y") int z) {
        return x + z;
    }
 
}
GET /sum?x=1&y=2
3
GET /sum?y=10&x=5&z=12345
15

HTTP server routes information:

Verb Path Zone Content type MVC View name Roles
GET /sum main json
Main.java
import org.rapidoid.setup.App;
 
public class Main {
 
    public static void main(String[] args) {
        App.bootstrap(args);
    }
 
}
Hello.java
@Controller
public class Hello {
 
    @Page("/")
    public String hello() {
        return "Hello, world!";
    }
 
}
GET /
Hello, world!
POST /
Hello, world!

HTTP server routes information:

Verb Path Zone Content type MVC View name Roles
GET POST / main html index
Main.java
import org.rapidoid.setup.App;
 
public class Main {
 
    public static void main(String[] args) {
        App.bootstrap(args);
    }
 
}
YourName.java
@Controller
public class YourName {
 
    @Page("/hi/{name}")
    public Screen hi(String name) {
        Tag msg = GUI.h4("Hi, ", GUI.i(name), "!");
        return GUI.page(msg).brand("What is your name?");
    }
 
}
GET /hi/Rapidoid

Hi, Rapidoid!

POST /hi/there

Hi, there!

HTTP server routes information:

Verb Path Zone Content type MVC View name Roles
GET POST /hi/{name} main html hi/name
Main.java
import org.rapidoid.setup.App;
 
public class Main {
 
    public static void main(String[] args) {
        App.bootstrap(args);
    }
 
}
Simple.java
@Controller
public class Simple {
 
    @Page
    public Object simple() {
        return "<p><b>RAW</b> HTML!<p>";
    }
 
}
GET /simple

RAW HTML!

HTTP server routes information:

Verb Path Zone Content type MVC View name Roles
GET POST /simple main html simple
Map<Integer, String> nums = U.map(1, "one", 5, "five");{"1":"one","5":"five"}
 
// Creating a grid (table) from the nums map
GUI.grid(nums);<GUI widget that generates HTML on .toString() call>KVGrid
Key Value
1 one
5 five
 
// Custom table headers
GUI.grid(nums).headers("Number", "As Text");<GUI widget that generates HTML on .toString() call>KVGrid
Number As Text
1 one
5 five
 
// Custom views for the keys and values
GUI.grid(nums)
        .keyView(k -> GUI.b(k))
        .valueView(v -> v + "!");<GUI widget that generates HTML on .toString() call>KVGrid
Key Value
1 one!
5 five!
GUI.btn("OK");<GUI widget that generates HTML on .toString() call>Btn
 
GUI.btn("Hey").primary();<GUI widget that generates HTML on .toString() call>Btn
 
GUI.btn(GUI.b("Delete")).danger();<GUI widget that generates HTML on .toString() call>Btn
 
GUI.btn(GUI.fa("cog"), " Something else").warning();<GUI widget that generates HTML on .toString() call>Btn
 
GUI.btn("Cancel").go("gui.html");<GUI widget that generates HTML on .toString() call>Btn
Map<String, Object> movie = U.map("Title", "Hackers", "cool", true);{"Title":"Hackers","cool":true}
 
// Creating a form to edit the movie map
GUI.edit(movie);<GUI widget that generates HTML on .toString() call>Form
 
// Adding form buttons
GUI.edit(U.map("Title", "")).buttons(GUI.btn("OK"));<GUI widget that generates HTML on .toString() call>Form
Main.java
import org.rapidoid.setup.App;
 
public class Main {
 
    public static void main(String[] args) {
        App.bootstrap(args);
    }
 
}
Movie.java
public class Movie {
    public String title;
    public int year;
}
Movies.java
@Controller
public class Movies {
 
    @Page("/")
    public Object movie() {
        Movie movie = new Movie();
        movie.title = "Chappie";
        movie.year = 2015;
 
        Form form = GUI.show(movie).buttons(GUI.btn("OK"));
        return GUI.page(form).brand("Movie details");
    }
 
}
GET /
Chappie
2015

HTTP server routes information:

Verb Path Zone Content type MVC View name Roles
GET POST / main html index
Main.java
import org.rapidoid.setup.App;
 
public class Main {
 
    public static void main(String[] args) {
        App.bootstrap(args);
    }
 
}
Movie.java
public class Movie {
    public String title;
    public int year;
}
Movies.java
@Controller
public class Movies {
 
    @Page("/")
    public Object movie() {
        Movie movie = new Movie();
        movie.title = "Chappie";
        movie.year = 2015;
 
        Btn save = GUI.btn("Save").primary();
        Form form = GUI.edit(movie).buttons(save);
        return GUI.page(form).brand("Edit movie details");
    }
 
}
GET /

HTTP server routes information:

Verb Path Zone Content type MVC View name Roles
GET POST / main html index
Main.java
import org.rapidoid.setup.App;
 
public class Main {
 
    public static void main(String[] args) {
        App.bootstrap(args);
    }
 
}
ParamGrid.java
@Controller
public class ParamGrid {
 
    @Page
    public Object table(Req req) {
        return GUI.page(GUI.grid(req.params())).brand("Request parameters");
    }
 
}
GET /table?name=Rambo&age=50&weapon=gun
Key Value
name Rambo
age 50
weapon gun

HTTP server routes information:

Verb Path Zone Content type MVC View name Roles
GET POST /table main html table
Main.java
import org.rapidoid.setup.App;
 
public class Main {
 
    public static void main(String[] args) {
        App.bootstrap(args);
    }
 
}
Bar.java
import org.rapidoid.annotation.Controller;
import org.rapidoid.annotation.GET;
 
import javax.inject.Inject;
 
@Controller("/bar")
public class Bar {
 
    @Inject
    public Foo foo;
 
    @GET("/hi")
    public String hello() {
        return foo.msg();
    }
 
    public String msg() {
        return "Hello from Bar!";
    }
 
}
Foo.java
import org.rapidoid.annotation.Controller;
import org.rapidoid.annotation.GET;
 
import javax.inject.Inject;
 
@Controller("/foo")
public class Foo {
 
    @Inject
    public Bar bar;
 
    private int count;
 
    @GET("/hi")
    public String hello() {
        return ++count + ": " + bar.msg();
    }
 
    public String msg() {
        return "Hello from Foo!";
    }
 
}
GET /foo/hi
"1: Hello from Bar!"
GET /bar/hi
"Hello from Foo!"
GET /foo/hi
"2: Hello from Bar!"

HTTP server routes information:

Verb Path Zone Content type MVC View name Roles
GET /bar/hi main json
GET /foo/hi main json
Main.java
import org.rapidoid.setup.App;
 
public class Main {
 
    public static void main(String[] args) {
        App.bootstrap(args);
    }
 
}
BootstrapLayout.java
@Controller
public class BootstrapLayout extends GUI {
 
    @Page("/")
    public Object layout() {
        Tag r1 = row(col4("A"), col4("B"), col4("C"));
        Tag r2 = row(col1("2/12"), col7("7/12"), col4("3/12"));
        Tag r3 = mid4("4/12 in the middle");
        return multi(r1, r2, r3);
    }
 
}
GET /
A
B
C
2/12
7/12
3/12
4/12 in the middle

HTTP server routes information:

Verb Path Zone Content type MVC View name Roles
GET POST / main html index
// Creating a list:
 
List<Integer> numbers = U.list(10, 20, 70);[10,20,70]
 
// Creating a set:
Set<String> words = U.set("abc", "xy", "rapidoid");["abc","xy","rapidoid"]
 
// Creating a map:
Map<Integer, String> nums = U.map(1, "one", 5, "five");{"1":"one","5":"five"}
List<Integer> words = U.list(10, 20, 30);[10,20,30]
 
Map<Integer, String> nums = U.map(1, "one", 5, "five");{"1":"one","5":"five"}
 
// U.isEmpty utils:
U.isEmpty(words);false
 
U.isEmpty(nums);false
// Is it empty or null:
 
String s = null;
U.isEmpty(s);true
 
U.isEmpty("");true
 
U.isEmpty("hey");false
Main.java
import org.rapidoid.commons.Env;
import org.rapidoid.config.Conf;
import org.rapidoid.gui.GUI;
import org.rapidoid.setup.App;
import org.rapidoid.setup.On;
 
import java.util.Map;
 
public class Main {
    public static void main(String[] args) {
        App.bootstrap("profiles=mysql,foo");
 
        On.get("/profiles").mvc(() -> GUI.display(Env.profiles()));
 
        Map<String, Object> myConfig = Conf.section("my").toMap();
        On.get("/my").mvc(() -> GUI.grid(myConfig));
    }
}
FooCtrl.java
import org.rapidoid.annotation.Controller;
import org.rapidoid.annotation.GET;
import org.rapidoid.annotation.Profiles;
 
@Controller
@Profiles("foo")
public class FooCtrl {
 
    @GET
    public String hi() {
        return "hi, FOO controller!";
    }
 
}
OtherCtrl.java
import org.rapidoid.annotation.Controller;
import org.rapidoid.annotation.GET;
import org.rapidoid.annotation.Profiles;
 
@Controller
@Profiles("default")
public class OtherCtrl {
 
    @GET
    public String hi() {
        return "hi, OTHER controller!";
    }
 
}
config-foo.yml
my:
  msg: 'hello from Foo!'
config.yml
app:
  navbar: false
 
my:
  msg: 'hello!'
  desc: 'simple example'
GET /profiles
 mysql
 foo
 dev
GET /my
Key Value
msg hello from Foo!
desc simple example
GET /hi
"hi, FOO controller!"

HTTP server routes information:

Verb Path Zone Content type MVC View name Roles
GET /hi main json
GET /my main html my
GET /profiles main html profiles
Main.java
import org.rapidoid.annotation.Valid;
import org.rapidoid.jpa.JPA;
import org.rapidoid.setup.App;
import org.rapidoid.setup.On;
 
public class Main {
 
    public static void main(String[] args) {
        App.bootstrap(args).jpa(); // bootstrap JPA
 
        On.get("/books").json(() -> JPA.of(Book.class).all()); // get all books
 
        On.post("/books").json((@Valid Book b) -> JPA.save(b)); // insert new book if valid
    }
 
}
Book.java
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.validation.constraints.NotNull;
 
@Entity
public class Book {
 
    @Id
    @GeneratedValue
    public Long id;
 
    @NotNull
    public String title;
 
    public int year;
 
}
config-default.yml
jdbc:
  driver: org.hsqldb.jdbc.JDBCDriver
  url: jdbc:hsqldb:mem:public
  username: sa
  password: ''
 
hibernate:
  dialect: org.hibernate.dialect.HSQLDialect
  connection:
    driver_class: org.hsqldb.jdbc.JDBCDriver
    url: jdbc:hsqldb:mem:public
    username: sa
    password: ''
config-dev.yml
hibernate:
  format_sql: false
  show_sql: true
 
c3p0:
  debug: true
 
hibernate:
  hbm2ddl:
    auto: update
config-mysql.yml
jdbc:
  driver: com.mysql.jdbc.Driver
  url: jdbc:mysql://localhost:3306/rapidoid
  username: root
  password: root
 
hibernate:
  dialect: org.hibernate.dialect.MySQL5Dialect
  connection:
    driver_class: com.mysql.jdbc.Driver
    username: root
    password: root
    url: jdbc:mysql://localhost:3306/rapidoid
config.yml
on:
  port: 8888
  address: 0.0.0.0
 
admin:
  port: same
  address: 0.0.0.0
 
app:
  domain: ''
  brand: App
  search: false
  navbar: true
  fluid: false
  cdn: auto # in DEV mode is false, in PRODUCTION is true
  contextPath: /
  home: /
  menu: {}
 
users:
  root:
    roles:
      - administrator
      - owner
    password: root # PLEASE change this

Let's send some HTTP requests and check the results:

POST /books {"title":"Java Book","year":2016}
{"id":1,"title":"Java Book","year":2016}
GET /books
[{"id":1,"title":"Java Book","year":2016}]
POST /books {"year":2004}
{"error":"Validation failed: Book.title (may not be null)","code":422,"status":"Unprocessable Entity"}
GET /books
[{"id":1,"title":"Java Book","year":2016}]

HTTP server routes information:

Verb Path Zone Content type MVC View name Roles
GET /books main json
POST /books main json
Name Desc Default value
config configuration filename prefix config
dev run in DEV mode auto-detected
production run in PRODUCTION mode auto-detected
test run in TEST mode auto-detected
secret=<SECRET> configure app-specific secret for encryption random
profiles=<P1,P2...> comma-separated list of application profiles (e.g. mysql,prod) the 'default' profile
on.port=<P> the default App server will listen at port P 8888
on.address=<ADDR> the default App server will listen at address ADDR 0.0.0.0
admin.port=<P> the Admin server will listen at port P same as on.port
admin.address=<ADDR> the Admin server will listen at address ADDR on.address
app.services=<S1,S2...> comma-separated list of services to bootstrap on the App server none
admin.services=<S1,S2...> comma-separated list of services to bootstrap on the Admin server none
MyApp.java
public class MyApp {
 
    public static void main(String[] args) {
        // Initialize the configuration
        App.args(args);
 
        On.get("/hi").json((Req req) -> req.data("name", "unknown"));
    }
 
}
On.setup().shutdown();
Echo.java
import org.rapidoid.net.TCP;
 
public class Echo {
 
    public static void main(String[] args) throws Exception {
        TCP.server().protocol(new EchoProtocol()).port(5555).build().start();
    }
 
}
EchoProtocol.java
import org.rapidoid.net.Protocol;
import org.rapidoid.net.abstracts.Channel;
 
public class EchoProtocol implements Protocol {
 
    @Override
    public void process(Channel ctx) {
        String line = ctx.readln().toUpperCase();
        ctx.write(line).write(CR_LF);
        ctx.closeIf(line.equals("BYE"));
    }
 
}

The following HTTP server features 2 web handlers:

Main.java
public class Main {
 
    public static void main(String[] args) throws Exception {
        new CustomHttpServer().listen(8080);
    }
 
}
CustomHttpServer.java
import org.rapidoid.buffer.Buf;
import org.rapidoid.http.AbstractHttpServer;
import org.rapidoid.http.HttpStatus;
import org.rapidoid.http.MediaType;
import org.rapidoid.net.abstracts.Channel;
import org.rapidoid.net.impl.RapidoidHelper;
 
public class CustomHttpServer extends AbstractHttpServer {
 
    private static final byte[] URI_PLAINTEXT = "/plaintext".getBytes();
 
    private static final byte[] URI_JSON = "/json".getBytes();
 
    private static final byte[] HELLO_WORLD = "Hello, World!".getBytes();
 
    @Override
    protected HttpStatus handle(Channel ctx, Buf buf, RapidoidHelper req) {
 
        if (req.isGet.value) {
            if (matches(buf, req.path, URI_PLAINTEXT)) {
                return ok(ctx, req.isKeepAlive.value, HELLO_WORLD, MediaType.TEXT_PLAIN);
 
            } else if (matches(buf, req.path, URI_JSON)) {
                return serializeToJson(ctx, req.isKeepAlive.value, new Message("Hello, World!"));
            }
        }
 
        return HttpStatus.NOT_FOUND;
    }
 
}
Message.java
public class Message {
 
    private final String message;
 
    public Message(String message) {
        this.message = message;
    }
 
    public String getMessage() {
        return message;
    }
 
}

The HTTP Request and Response API (in interface Req):

HTTP REQUEST DATA
String verb()
Gets the verb of the HTTP request.
String uri()
Gets the uri of the HTTP request.
String path()
Gets the path of the HTTP request.
String query()
Gets the query of the HTTP request.
byte[] body()
Gets the raw body data of the HTTP request.
String host()
Gets the value of the Host header of the HTTP request.
String zone()
Gets the name of the application zone handling the request.
The default zone name is main for the On API, and admin for the Admin API.
String contextPath()
Gets the context path of the application zone handling the request.
The default context path is / for the On API, and /_ for the Admin API.
String clientIpAddress()
Gets the IP address of the HTTP client sending the request.
long connectionId()
Gets the HTTP connection ID, which is unique per HTTP server instance.
long requestId()
Gets the HTTP request ID, which is unique per HTTP server instance.
URL PARAMETERS:
Map<String, String> params()
Gets the URL parameters of the HTTP request.
String param(String name)
Returns the value of the specified mandatory URL parameter from the HTTP request, or throws a runtime exception if it is not found.
String param(String name, String defaultValue)
Returns the value of the specified optional URL parameter from the HTTP request, or the specified default value, if not found.
T param(Class<T> beanType)
Returns a new instance of the specified bean type, with properties initialized from the URL parameters of the HTTP request.
POSTED PARAMETERS IN THE REQUEST BODY:
Map<String, Object> posted()
Gets the posted parameters of the HTTP request body.
T posted(String name)
Returns the value of the specified posted parameter from the HTTP request body, or throws a runtime exception if it is not found.
T posted(String name, T defaultValue)
Returns the value of the specified posted parameter from the HTTP request body, or the specified default value, if it is not found.
T posted(Class<T> beanType)
Returns a new instance of the specified bean type, with properties initialized from the posted parameters of the HTTP request.
UPLOADED FILES IN THE REQUEST BODY:
Map<String, List<Upload>> files()
Gets the uploaded files from the HTTP request body.
List<Upload> files(String name)
Returns the uploaded files with the specified form parameter name (not filename) from the HTTP request body, or throws a runtime exception if not found.
Upload file(String name)
Returns exactly one posted file with the specified form parameter name (not filename) from the HTTP request body, or throws a runtime exception if not found.
REQUEST DATA PARAMETERS (URL PARAMETERS + POSTED PARAMETERS + UPLOADED FILES):
Map<String, Object> data()
Gets the data parameters (URL parameters + posted parameters + uploaded files) of the HTTP request.
T data(String name)
Returns the value of the specified data parameter from the HTTP request, or throws a runtime exception if it is not found.
T data(String name, T defaultValue)
Returns the value of the specified data parameter from the HTTP request, or the specified default value, if it is not found.
T data(Class<T> beanType)
Returns a new instance of the specified bean type, with properties initialized from the data parameters of the HTTP request.
EXTRA ATTRIBUTES ATTACHED TO THE REQUEST:
Map<String, Object> attrs()
Gets the extra attributes of the HTTP request.
T attr(String name)
Returns the value of an extra attribute from the HTTP request, or throws a runtime exception if it is not found.
T attr(String name, T defaultValue)
Returns the value of the specified extra attribute from the HTTP request, or the specified default value, if it is not found.
SERVER-SIDE SESSION:
String sessionId()
Returns the ID of the session (the value of the "JSESSIONID" cookie). If a session doesn't exist, a new session is created.
boolean hasSession()
Does the HTTP request have a server-side session attached?
Map<String, Serializable> session()
Provides read/write access to the server-side session attributes of the HTTP request/response.
T session(String name)
Returns the value of the specified server-side session attribute from the HTTP request/response, or throws a runtime exception if it is not found.
T session(String name, T defaultValue)
Returns the value of the specified server-side session attribute from the HTTP request/response, or the specified default value, if it is not found.
TOKEN DATA:
boolean hasToken()
Does the HTTP request have a token attached?
Map<String, Serializable> token()
Provides read/write access to the token attributes of the HTTP request/response.
T token(String name)
Returns the value of the specified token attribute from the HTTP request/response, or throws a runtime exception if it is not found.
T token(String name, T defaultValue)
Returns the value of the specified token attribute from the HTTP request/response, or the specified default value, if it is not found.
REQUEST HEADERS:
Map<String, String> headers()
Gets the headers of the HTTP request.
String header(String name)
Returns the value of the specified header from the HTTP request, or throws a runtime exception if it is not found.
String header(String name, String defaultValue)
Returns the value of the specified header from the HTTP request, or the specified default value, if it is not found.
REQUEST COOKIES:
Map<String, String> cookies()
Gets the cookies of the HTTP request.
String cookie(String name)
Returns the value of the specified cookie from the HTTP request, or throws a runtime exception if it is not found.
String cookie(String name, String defaultValue)
Returns the value of the specified cookie from the HTTP request, or the specified default value, if it is not found.
RESPONSE:
Resp response()
Gets the reference to the response object.
ASYNCHRONOUS REQUEST HANDLING:
Req async()
Informs the HTTP server that the request will be handled asynchronously (typically on another thread). When the response is complete, the Req#done() or Resp#done() method must be called, to inform the server.
boolean isAsync()
Is/was the request being handled in asynchronous mode?
Req done()
Informs the HTTP server that the asynchronous handling has finished and the response is complete.
boolean isDone()
Has the request handling and response construction finished?
WEB APPLICATION SETUP:
HttpRoutes routes()
Provides access to the HTTP routes of the web application setup.
Route route()
Provides access to the matching HTTP route (if any) of the web application setup.
In case a generic handler handles the request, or no matching route was found, null is returned.
Customization custom()
Provides access to the customization of the web application setup.
void revert()
Reverts the previous processing of the request, usually with intention to process the same request again.
OutputStream out()
First renders the response headers, then returns an OutputStream representing the response body. The response body will be constructed by writing to the OutputStream.
MediaType contentType()
Gets the Content-Type header of the HTTP response if it has been assigned, or the default value as configured in the HTTP route.

The HTTP Request and Response API (in interface Resp):

Resp result(Object content)
Sets the content to be serialized into a body when the HTTP response is rendered.
Object result()
Gets the content to be serialized into a body when the HTTP response is rendered.
Resp body(byte[] body)
Sets the HTTP response body from a byte[] data that is written as a HTTP response body when rendered.
Resp body(ByteBuffer body)
Sets the HTTP response body from a ByteBuffer data that is written as a HTTP response body when rendered.
Object body()
Gets the HTTP response body data (of type byte[] or ByteBuffer) that is written as a HTTP response body when rendered.
Resp raw(byte[] raw)
Sets the raw HTTP response (headers and body) from a byte[] data that is written as a HTTP response when rendered.
Resp raw(ByteBuffer raw)
Sets the raw HTTP response (headers and body) from a ByteBuffer data that is written as a HTTP response when rendered.
Object raw()
Gets the raw HTTP response (headers and body) data (of type byte[] or ByteBuffer) that is written as a HTTP response when rendered.
Resp code(int code)
Sets the status code (e.g. 200, 404, 500) of the HTTP response.
int code()
Gets the status code (e.g. 200, 404, 500) of the HTTP response.
Resp contentType(MediaType contentType)
Sets the Content-Type header to be rendered in the HTTP response.
MediaType contentType()
Gets the Content-Type header to be rendered in the HTTP response.
Resp redirect(String redirectURI)
Sets the redirect URI of the HTTP response.
Setting this will cause a HTTP 30x redirect response.
String redirect()
Gets the redirect URI of the HTTP response.
Resp filename(String filename)
Sets the filename when serving a file in the HTTP response.
String filename()
Gets the filename when serving a file in the HTTP response.
Resp view(String viewName)
Sets a custom name of the view (V from MVC) of the HTTP response.
This also sets mvc to true.
The default view name equals the request path without the "/" prefix, except for the "/" path, where the view name is "index".
E.g. "/abc" -> "abc", "/" -> "index", "/my/books" -> "my/books".
String view()
Gets the (default or customized) name of the view (V from MVC) of the HTTP response.
The default view name equals the request path without the "/" prefix, except for the "/" path, where the view name is "index".
E.g. "/abc" -> "abc", "/" -> "index", "/my/books" -> "my/books".
Resp noView()
Disables the view rendering for the target MVC route. The page decorator remains enabled.
Resp file(File file)
Sets the file to be served when the HTTP response is rendered.
File file()
Gets the file to be served when the HTTP response is rendered.
Map<String, String> headers()
Provides read/write access to the headers of the HTTP response.
Resp header(String name, String value)
Sets a header of the HTTP response.
Map<String, String> cookies()
Provides read/write access to the cookies of the HTTP response.
Resp cookie(String name, String value, String... extras)
Sets a cookie of the HTTP response.
Map<String, Serializable> session()
Provides read/write access to the server-side session attributes of the HTTP request/response.
Resp session(String name, Serializable value)
Sets a session attribute of the HTTP response.
Map<String, Serializable> token()
Provides read/write access to the token attributes of the HTTP request/response.
Resp token(String name, Serializable value)
Sets a token attribute of the HTTP response.
Map<String, Object> model()
Provides read/write access to the model (M from MVC) that will be rendered by the view renderer.
Resp model(String name, Object value)
Sets an attribute of the model (M from MVC) that will be rendered by the view renderer.
Resp done()
Informs the HTTP server that the asynchronous handling has finished and the response is complete.
Alias to request().done().
Resp plain(Object content)
Sets the Content-Type: text/plain; charset=utf-8 header and the content of the HTTP response.
Alias to contentType(MediaType.PLAIN_TEXT_UTF_8).body(content).
Resp html(Object content)
Sets the Content-Type: text/html; charset=utf-8 header and the content of the HTTP response.
Alias to contentType(MediaType.HTML_UTF_8).body(content).
Resp json(Object content)
Sets the Content-Type: application/json header and the content of the HTTP response.
Alias to contentType(MediaType.JSON).body(content).
Resp binary(Object content)
Sets the Content-Type: application/octet-stream header and the content of the HTTP response.
Alias to contentType(MediaType.BINARY).body(content).
boolean mvc()
Checks whether the response model and view will be rendered in a MVC fashion.
A typical renderer would use Resp#view to get the view name, and Resp#model to get the model. A custom view renderer can be configured/implemented via the On.custom().viewResolver(...) method.
Resp mvc(boolean mvc)
Sets whether the response model and view will be rendered in a MVC fashion.
A typical renderer would use Resp#view to get the view name, and Resp#model to get the model. A custom view renderer can be configured/implemented via the On.custom().viewResolver(...) method.
OutputStream out()
First renders the response headers, then returns an OutputStream representing the response body. The response body will be constructed by writing to the OutputStream.
Req request()
Gets the reference to the request object.
boolean login(String username, String password)
Initiates a user login process with the specified username and password.
After a successful login, the username will be persisted in the token.
Returns information whether the login was successful
void logout()
Initiates a user logout process, clearing the login information (username) from the token.
Screen screen()
Provides access to the screen model for custom (MVC) page rendering.