原文(投稿日：2019/07/19)へのリンク

Javalinは、KotlinとJavaのための軽量なWebフレームワークだ。デフォルトではシンプルなブロック方式で設計されており、WebSocket、HTTP2、非同期リクエストをサポートする。SparkJavaフレームワークのフォークとして始められたが、JavaScriptフレームワークkoa.jsの影響を受けて、すぐにゼロから書き換えられた。

JavalinはJetty上に構築されており、パフォーマンスは素のJettyコードとほとんど変わらない。クラスを拡張したり、@アノテーションを使用したり、JavaとKotlin用で別々のバージョンをダウンロードしたりする必要もない。

Javaを使用する場合は、以下のような" public static void main "があればよい。

public static void main(String[] args) { var app = Javalin.create().start(7000); app.get("/", ctx -> ctx.result("Hello World")); }

いくつかの設定をコード例で見てみよう。

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

パスパラメータ、クエリパラメータ、フォームパラメータなどのパラメータの検証は非常に簡単だ。

var myQpStr = ctx.queryParam("my-qp"); // no validation, returns String or null var myQpInt = ctx.pathParam("my-qp", Integer.class).get(); // returns an Integer or throws var myQpInt = ctx.formParam("my-qp", Integer.class).check(i -> i > 4).get(); // Integer > 4 // validate two dependent query parameters: var fromDate = ctx.queryParam("from", Instant.class).get(); var toDate = ctx.queryParam("to", Instant.class) .check(it -> it.isAfter(fromDate), "'to' has to be after 'from'") .get(); // validate a json body: var myObject = ctx.bodyValidator(MyObject.class) .check(obj -> obj.myObjectProperty == someValue) .get();

Javalinのもうひとつの興味深い機能は、他のフレームワークにも存在するハンドラだ。Javalinには、beforeハンドラ、endpointハンドラ、afterハンドラ、例外ハンドラ、エラーハンドラが用意されている。

//before handlers app.before(ctx -> { // runs before all requests }); app.before("/path/*", ctx -> { // runs before request to /path/* }); //endpoint handlers app.get("/", ctx -> { // some code ctx.json(object); }); app.get("/hello/*", ctx -> { // capture all request to sub-paths of /hello/ }); //after handlers app.after(ctx -> { // run after all requests }); app.after("/path/*", ctx -> { // runs after request to /path/* });

認証や承認処理を行うために、Javalinには、機能インターフェースとして AccessManager が用意されている。開発者が必要に応じて、独自のアクセスマネージャを実装することも可能だ。

// Set the access-manager that Javalin should use: 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) { // determine user role based on request // typically done by inspecting headers } 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)); });

バージョン3.0以降では、OpenAPI(Swagger)プラグインも提供されており、OpenAPI 3.0仕様の完全な実装をDSLとアノテーションの両方で利用できる。

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

Javalinアプリケーションのデプロイは、( maven-assembly-plugin を使って)依存関係のあるjarを作成して、" java -jar filename.jar "でjarを起動すればよい。Jettyサーバを組み込みで持っているため、アプリケーションサーバは不要だ。

Javalinには教育者専用のページも用意されている。その中では、JavalinにはJettyサーバが組み込まれており、サーブレットコンテナ/アプリケーションサーバを構成する必要なくコーディングを始めることができるので、学生にとってメリットがあることが強調されている。

GraalVMでの実行やKotlin CRUD REST APIなど、一連のチュートリアルも提供されている。チュートリアルページには、その完全な一覧がある。

詳細はドキュメントページを参照して頂きたい。Javalinはmaven経由あるいは手動でmaven centralからダウンロードできる。