O Javalin é um framework web leve para o Java e Kotlin, projetado para ser simples, que suporta websockets, HTTP2, e requisições assíncronas. O Javalin começou como um fork do framework SparkJava, mas rapidamente foi reescrito, influenciado pelo framework JavaScript koa.js.
O Javalin é construído em cima do Jetty e tem performance parecida com a do Jetty sem nenhuma aplicação. Além disso, os desenvolvedores não precisam estender nenhuma classe, usar @Annotations, ou mesmo baixar binários diferentes do framework para codificar em Java ou Kotlin.
Para iniciar com o Javalin em Java, os desenvolvedores somente precisam de um método public static void main
conforme a abaixo:
public static void main(String[] args) {
var app = Javalin.create().start(7000);
app.get("/", ctx -> ctx.result("Hello World"));
}
Vamos dar uma olhada em um trecho de código com algumas configurações adicionais:
var app = Javalin.create(config -> {
config.defaultContentType = "application/json";
config.autogenerateEtags = true;
config.addStaticFiles("/public");
config.asyncRequestTimeout = 10_000L;
config.dynamicGzip = true;
config.enforceSsl = true;
}).routes(() -> {
path("users", () -> {
get(UserController::getAll);
post(UserController::create);
path(":user-id"(() -> {
get(UserController::getOne);
patch(UserController::update);
delete(UserController::delete);
});
ws("events", userController::webSocketEvents);
});
}).start(port);
É muito simples validar parâmetros tais como, path params, query params, e form params no Javalin:
var myQpStr = ctx.queryParam("my-qp"); // sem validação, retorna String ou null
var myQpInt = ctx.pathParam("my-qp", Integer.class).get(); // retorna um Integer ou lança exceção
var myQpInt = ctx.formParam("my-qp", Integer.class).check(i -> i > 4).get(); // Integer > 4
// valida dois query parameters dependentes:
var fromDate = ctx.queryParam("from", Instant.class).get();
var toDate = ctx.queryParam("to", Instant.class)
.check(it -> it.isAfter(fromDate), "'to' tem que ser após 'from'")
.get();
// valida um a corpo json:
var myObject = ctx.bodyValidator(MyObject.class)
.check(obj -> obj.myObjectProperty == someValue)
.get();
Outra funcionalidade interessante no Javalin que existe em outros frameworks são os Handlers. O Javalin traz before-handlers, endpoint-handlers, after-handlers, exception-handlers e error-handlers.
//before handlers
app.before(ctx -> {
// executa antes de todas requests
});
app.before("/path/*", ctx -> {
// executa antes da request /path/*
});
//endpoint handlers
app.get("/", ctx -> {
ctx.json(object);
});
app.get("/hello/*, ctx -> {
// captura todas requests para o sub-paths de /hello/
});
//after handlers
app.after(ctx -> {
// executa após todas requests
});
app.after("/path/*", ctx -> {
// executa após a request /path/*
});
Para lidar com autenticação/autorização, o Javalin traz a interface funcional AccessManager
, na qual os desenvolvedores podem implementar seus próprios controles de acesso da maneira que preferirem.
// ajusta o controle de acesso que o Javalin deve usar
app.accessManager((handler, ctx, permittedRoles) -> {
MyRole userRole = getUserRole(ctx);
if (permittedRoles.contains(userRole)) {
handler.handle(ctx);
} else {
ctx.status(401).result("Unauthorized");
}
});
Role getUserRole(Context ctx) {
}
enum MyRole implements Role {
ANYONE, ROLE_ONE, ROLE_TWO, ROLE_THREE;
}
app.routes(() -> {
get("/un-secured", ctx -> ctx.result("Hello"), roles(ANYONE));
get("/secured", ctx -> ctx.result("Hello"), roles(ROLE_ONE));
});
Desde a versão 3.0, o Javalin também tem um plugin para o OpenAPI (Swagger). A implementação completa da especificação do OpenAPI 3.0 está disponível tanto como uma DSL e annotations.
OpenAPI DSL:
val addUserDocs = document()
.body()
.result("400")
.result("204")
fun addUserHandler(ctx: Context) {
val user = ctx.body()
UserRepository.addUser(user)
ctx.status(204)
}
OpenAPI annotations:
@OpenApi(
requestBody = OpenApiRequestBody(User::class),
responses = [
OpenApiResponse("400", Unit::class),
OpenApiResponse("201", Unit::class)
]
)
fun addUserHandler(ctx: Context) {
val user = ctx.body()
UserRepository.createUser(user)
ctx.status(201)
}
Para publicar uma aplicação Javalin, os desenvolvedores somente precisam criar um jar com suas dependências (usando o maven-assembly-plugin
), então executar o jar com java -jar filename.jar
, o Javalin tem um servidor Jetty embutido, de forma que nenhum servidor de aplicação é necessário.
O Javalin também tem uma página dedicada para educadores, que enfatiza que os estudantes podem se beneficiar do Javalin, dado que não é necessário nenhum Servlet Container/Application Server, uma vez que o Jetty é embutido no Javalin.
Existem alguns tutoriais disponíveis, tais como Running on GraalVM, e Kotlin CRUD REST API, a lista completa de exemplos pode ser encontrada na página de tutoriais.
Maiores detalhes sobre o Javalin podem ser encontrados na página da documentação. É possível realizar o download do Javalin via maven ou manualmente através do maven central.