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

What's new in v5.1?

There's so much new & cool stuff in Rapidoid v5.1:

  • automatic hot reload when the source code changes,
  • lambdas as handlers - with named and type-safe parameters,
  • URI path patterns (simple and regex-based),
  • Admin Center for convenient management of the deployed app,
  • JVM and OS metrics in the Admin Center,
  • info about the web app routes in the Admin Center,
  • role-based web security with out-of-the-box login / logout,
  • configuration info in the Admin Center,
  • configuration profiles,
  • improved dependency injection (with profile support),
  • easy JPA bootstrap with TX management and nice utils like JPA.insert(new Foo()),
  • redesigned and enhanced JDBC utils,
  • scaffolding of JPA entities (RESTful services and management GUI),
  • new templating language and engine - similar to Mustache, but more practical,
  • highly customizable setup (serialization, security, error handling, template engine...),
  • many GUI enhancements...
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;
 
}

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