Rapidoid - Old Documentation / Examples

1 RESTful service one-liner

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

2 Instant web application

// On GET /hi or POST /hi return a "Hello World" web page
On.page("/hi").mvc("Hello <b>world</b>!");
config.yml
gui:
  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

3 More control over the HTTP server setup

On.address("127.0.0.1").port(9999);
 
On.get("/x").json("x"); // continue with normal setup

4 HTTP handlers and routing

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

5 All the request data is in the (Req req) parameter

// 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.

6 Rendering a HTTP response

// 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; charset=utf-8 header and the content of the HTTP response.
Alias to contentType(MediaType.JSON).body(content).

7 High-level annotation-based POJO controllers

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"

8 Exception handlers

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!

9 MVC architecture with Rapidoid's built-in template engine

Rapidoid's template engine

  • Starting from v5.1, Rapidoid includes new templating engine.
  • Basically, it is very similar to Mustache, with the following differences.
  • 1. Using ${x} instead of {{x}}. This avoids collision of the {{x}} tags with the front-end libraries (e.g. Angular).
  • 2. Supporting additional {{?x}}...{{/x}} tag for if. The traditional {{#x}}...{{/x}} remains unchanged, having both foreach and if semantics.
  • 3. Providing text alternative if the value if not available e.g. ${x|something else}.
// 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.

10 Serving static files from the default locations

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!
static/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

11 Role-based security

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

12 Server-side session (a.k.a. Session)

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.

13 Client-side Token as a session

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.

14 Manipulating the response content type

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.

15 Manipulating the response code

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.

16 Request wrappers (interceptors)

// 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

17 Returning a "Not Found" result

// 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

18 Generic handlers match any request

// 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}]

19 Asynchronous request processing

// 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().

20 URL pattern matching

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

21 Automatic JSON Serialization of Data Structures

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

22 Automatic Construction and Serialization of JavaBeans

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

23 Named URL Parameters

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

24 Hello, web pages!

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

25 Building HTML pages with Java

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

26 Raw HTML pages

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

27 Creating a Two-column Grid from a Map

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!

28 Constructing buttons

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

29 Creating a form from a Map

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

30 Display bean properties

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

31 Edit bean properties

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

32 Create key-value data grid from a Map

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

33 Dependency injection of singletons

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

34 Bootstrap-based GUI layout

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

35 Creating collections

// 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"}

36 Collection utils

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

37 String utils

// Is it empty or null:
 
String s = null;
U.isEmpty(s);true
 
U.isEmpty("");true
 
U.isEmpty("hey");false

38 Application Profiles

Main.java
import org.rapidoid.config.Conf;
import org.rapidoid.env.Env;
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(args, "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
gui:
  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

39 Configuring Rapidoid

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:
  home: /
  contextPath: /
 
gui:
  domain: ''
  brand: App
  search: false
  navbar: true
  fluid: false
  cdn: auto # in DEV mode is false, in PRODUCTION is true
  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

40 Server Configuration

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 secret key for cryptography 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.run(args);
 
        On.get("/hi").json((Req req) -> req.data("name", "unknown"));
    }
 
}

41 Stopping the server

On.setup().shutdown();

42 Implementing Echo protocol

Rapidoid as a Network Protocol Framework

You can use Rapidoid as a Network Protocol Framework, to implement your custom TCP-based protocols.

For a quick and easy start, please take a look at the following Echo protocol example:

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"));
    }
 
}

43 Building the fastest HTTP server

Module rapidoid-http-server: HTTP Server & Low-level Web Framework

Built on top of Java NIO from scratch

The low-level HTTP API provides access to the extremely fast Rapidoid HTTP server components.

Rapidoid is implemented on top of Java NIO, without native libraries, nor external dependencies.

It is great to see how Java performance can match C++ and outperform all the other languages in network programming.

Designed for performance from day 1

Rapidoid was designed for high performance since its inception, and several parts of it played a critical role:

  • asynchronous I/O processing,
  • minimizing the garbage collection pressure,
  • fast object pools,
  • reusable off-heap buffers,
  • very fast and efficient HTTP parser,
  • and many other optimizations.

Going low-level for ultimate performance

If we want to implement any protocol in the fastest way posible, then we need to do it on a lower level of abstraction.

Let's see how we can implement one of the fastest web servers in the world! (based on transparent TechEmpower benchmarks)

The following HTTP server features 2 web handlers:

Main.java
import org.rapidoid.net.Server;
 
public class Main {
 
    public static void main(String[] args) throws Exception {
        Server server = new CustomHttpServer().listen(5050);
 
        // Not doing any work now, so shutdown
        server.shutdown();
    }
 
}
CustomHttpServer.java
import org.rapidoid.buffer.Buf;
import org.rapidoid.http.AbstractHttpServer;
import org.rapidoid.http.HttpStatus;
import org.rapidoid.http.HttpUtils;
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(HttpUtils.noReq(), 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;
    }
 
}

44 API documentation

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 directly sending the request.
This can be the address of a real user, or a HTTP proxy (if the user uses such), or a reverse proxy (if the application/server uses such).
String realIpAddress()
A best-effort attempt to infer the real IP address of the end user/client/client proxy.
If a reverse proxy is detected with high confidence (or configured), its headers will be used to get the real IP address of the user.
Otherwise, the value of Req#clientIpAddress() is returned.
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.
long handle()
Returns the request handle, which is used when resuming the request handling in asynchronous way.
See Resp#resume.

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.
void resume(AsyncLogic asyncLogic)
Resumes the asynchronous request handling.