「SpringBoot」に疲れたら「jooby」はいかが？

[jooby]:https://jooby.org/
[sp]:http://sparkjava.com/
[netty]:https://netty.io/
[mod]:https://jooby.org/modules/
[modules_FREEMARKER]:https://jooby.org/doc/ftl/
[Freemarker]:https://freemarker.apache.org/
[modules_JACKSON]:https://jooby.org/doc/jackson/

[mod_redis]:https://jooby.org/doc/session/#redis-session-store

最近かかわったプロジェクトでは、「SpringBoot」(もしく「Spring Web」)の採用が多くデファクトスタンダードになってきたように感じています。
「SpringBoot」が提供しくれているたくさんの機能には大変お世話になっているのですが、不満も多いです。

例えば以下のようなものです。

* 設定が「アノテーションで簡単になった」とはいえ、呪文のようなプロパティー設定まみれ。
* DIのメリットはトランザクション管理だけど、今となっては Loanパターン (try-with-resources構文みたいなやつ)で実現したほうがわかりやすいしはまりにくい。
* J2EE仕様なんていう化石化したIF使いたくない
* DIの魔法の奥で発生した分けのわからない例外に多大な時間が奪われる
* spring のデフォルトの使い方から外れると、急にハードルが上がる

たまたま出会った、 [jooby]っていうのを試してみて、好印象だったのでご紹介します。

- - - - - - - -

Joobyとは
-------------------------

* 公式サイト : https://jooby.org/

パスを「レスポンスに変換する関数」に割り当てることを主眼にしているフレームワークです。    

公式サイトでは「javaで作る、スケーラブルで 早くて モジュール志向で マイクロフレームワーク だ」と言っています。  
マイクロフレームワークなどと言われると 「buzzword っぽくて胡散臭い」と思ったのですが、  
使ってみると「コンパクトに作り始めて拡張も容易」なフレームワークだと思いました。  

また、実際にアプリを実行してみたところ、起動も早く「マイクロフレームワークの風」を感じました。  ([netty] ベースのサーバが起動します )  


### 公式サイトのサンプルソース ###

#### Javaサンプル
```
import org.jooby.Jooby;
public class App extends Jooby {
  { get("/", () -> "Hey Jooby!"); }
  public static void main(final String[] args) {
    run(App::new, args);
  }
}
```
これだけでWebアプリのサーバが起動します。
また、標準的に **kotlinもサポートしている** ところが素敵です。

#### Kotlinサンプル ####
```
import org.jooby.*
class App : Kooby ({
    get("/") { "Hey Jooby!" }
})
fun main(args:Array<String>) {  run(::App, *args) }
```

このブログでは以下 kotlin のソースで紹介していきます。

- - - - - - -

ルーティング実装
-------------------------

上の 「Kotlinサンプル」の `get("/") { "Hey Jooby!" }` がルーティング実装です。 ルートパス にアクセスすると  `Hey Jooby!` という文字列返却されるという意味です。(直観的でとても分かりやすい)   

```
    get("/hoge") { "hogeres" }
    post("/foo/boo") { FooControler.boo() }
```
というような実装をしていけば、Webアプリ完成ということになります。

以下、少しだけ複雑な例です。
(「リクエストや、レスポンスに対するハンドリング」「テンプレートエンジン使う」場合)

```
get("/boo/hoge") { req , rsp -> BooControler.hoge(req.param("name") , rsp)
    Results.html("freemarker/boo/hoge.html")
}
```

簡単なことも難しいことも直観的に実装できるところがいいと思います。


- - - - - - -

ルーティング以外の実装
-------------------------

ルーティング以外の、使いそうな実装を紹介していきます。

### 例外ハンドリング ###

例外が発生した場合、何をレスポンスするかを実装できます。

```
err { req, rsp, err ->
    val cause = err.cause
    when (cause) {
      is MyException1 -> { /* レスポンス実装 */ }
      is MyException2 -> { /* レスポンス実装 */ }
      else -> Err.DefHandler().handle(req, rsp, err)
    }
}
```

特定の例外のみハンドリングしたい場合は以下のようにすることもできます。

```
err(MyException1::class.java) { req, rsp, err -> /* 省略 */}
```

### Filter ###

リクエストの処理前後に、フィルター処理を挟むことができます。これにより、アクセスログを出力したり、HTTPヘッダーやクッキーを、一律もしくは条件付きで 付与することができます。


```
before("**") { req, rsp -> initLoginfo(req, rsp) }

after("**") { req, rsp, result ->
    accessLog(req, rsp, result)
            .header("Access-Control-Allow-Origin", appEnv.allowOrigin)
            .header("Access-Control-Allow-Credentials", true)
}
```


- - - - - -

MODULES
---------------------

[jooby] は使用する「モジュール」 を指定することによって機能拡張する思想です。
標準的にサポートしているものが [公式サイトのMODULES][mod] に書かれています。

Maven や gradle の dependency 設定をして、ルーティングの前あたりに、
`use( ＜モジュールのインスタンス＞ )` というように実装して機能追加する使い方が基本です。

以下少し例を上げます。


### Freemarker テンプレートエンジンに使う ###

* 公式サイトのドキュメント ... [modules_FREEMARKER]

以下のようにコーディングしておくと Freemarker のテンプレートが使えます。

```
    use(Ftl("/freemarker"))
```
上の例では、
classpath が通っているディレクトリから `freemarker` ディレクトリ以下に、テンプレートを見に行きますという意味になります。

実際にテンプレートを使う場合、以下のようにコードを書くことになります。

```
get("/hoge/") {
    Results.html("hoge/index.html")
            .put("hogeParam", hogeBoo.hoge)
}
```

上の例では、テンプレートファイル `freemarker/hoge/index.html` の中で、 変数 `${hogeParam}` のようにしてオブジェクトにアクセスできるようになります。  ( [Freemarker] の標準的な使い方ができます)

### RESTish な APIのために jackson を使う ###

* 公式サイトのドキュメント ... [modules_JACKSON]

以下のようにコーディングしておくと

```
    use(Jackson())
```

`get("/myjson") { MyJsonObject( firstName ="Yamada", name ="tarou", age ="25") }` というようなコードを書くだけで json としてレスポンスが返されるようになり、RESTish APIが作りやすくなります。  

ただし、単なる文字列を返却したい場合、返却値が ダブルクォーテーション でくくられる ようなふるまいになってしまいました。
(例えば、 `get("/alive/chek") { "I'm alive" }` とすると、 レスポンスの文字列が `"I'm alive"` となってしまう)  

json 以外のレスポンスも返却したい場合は、 `use(Jackson())` を使わず、自力でJackson に json成形させたほうがいいように思います。




- - - - - -

その他の micro web framework
------------------


"micro web framework" としては他に [Spark Framework][sp] というものも人気があり、
パスを レスポンス にマッピングするという思想が、[jooby] と似ています。

簡単さという点では、 [jooby] よりもさらに簡単です。
ただ、細かいハンドリングが場合は [jooby] のほうがやり易そうです。また、 [MODULES][mod] による拡張性の面でも [jooby] のほうに軍配が上がるかと思います。

利用する局面に応じて どちらがいいか比較してみてください。

- - - - - -

[jooby] いかがでししたでしょうか。

それでは ごきげんよう

- - - - -

### 関連ページ ###

* [Webフレームワーク Jooby と Kotlin の組み合わせがいい](https://ti.que.jp/p/2018/09/17/jooby_kotlin/)    
    * [グループ分けアプリ](https://ti.que.jp/div/)