Ratpack入門 (3) - hello world 詳解

## Ratpack入門シリーズ

1. [Ratpack入門 (1) - Ratpackとは](https://qiita.com/minebreaker/items/d7eeca815872a97069f5)
2. [Ratpack入門 (2) - アーキテクチャー](https://qiita.com/minebreaker/items/a9b256fd8a1513104669)
3. [Ratpack入門 (3) - hello world 詳解](https://qiita.com/minebreaker/items/b26d7d0677f91f17a7b5)
4. [Ratpack入門 (4) - ルーティング & 静的コンテンツ](https://qiita.com/minebreaker/items/8f26d8350f936ad669c2)
5. [Ratpack入門 (5) - Json & Registry](https://qiita.com/minebreaker/items/4353611cc541e3cb35fb)
6. [Ratpack入門 (6) - Promise](https://qiita.com/minebreaker/items/4689058d0d7b34d99c74)
7. [Ratpack入門 (7) - Guice & Spring](https://qiita.com/minebreaker/items/52b303bc18db5b33bd68)
8. [Ratpack入門 (8) - セッション](https://qiita.com/minebreaker/items/1ebaa492b257365e1e5e)
9. [Ratpack入門 (9) - Thymeleaf](https://qiita.com/minebreaker/items/50693a4d6614979f654c)


## hello world 詳解

ここでは、[最初の記事](https://qiita.com/minebreaker/items/d7eeca815872a97069f5)のHello Worldサンプルをもう少し複雑にして、Ratpackという「水に慣れる」ことを目指します。

なおここでは型を明示するため、あえて冗長に書いています。石を投げないでください。

```java
public final class Sample3_HelloWorldRevisited {


    public static void main( String[] args ) throws Exception {

        ServerConfig config = ServerConfig.builder()
                                          .port( 5050 )
                                          .connectTimeoutMillis( 10000 )
                                          .threads( 8 )
                                          .development( true )
                                          .build();

        Registry registry = Registry.empty();

        Action<Chain> handlers = ( Chain chain ) -> {

            Handler handler = ( Context ctx ) -> {
                ctx.render( "hello, world" );
            };

            chain.get( handler );
        };

        RatpackServer.of( spec -> spec.serverConfig( config )
                                      .registry( registry )
                                      .handlers( handlers ) )
                     .start();
    }

}
```


## `ServerConfig`

サーバーの設定を変更するためのクラスです。ポート番号などがここから設定できます。

`ServerConfigBuilder`が用意されているのでこれを使うのが一番簡単だと思います。
`json()`、`yaml()`等、ファイルから設定値を読み込むためのメソッドも用意されています。
他にもシステムプロパティーや引数などから設定するためのメソッドがあるので、好みの方法で`ServerConfig`を作成できます。


### `development(boolean)`

開発中モードを有効化するフラグです。
有効な場合、エラー発生時のハンドラーが自動的に追加されます。
※いまいちドキュメント化されていないので、他にも違いがあるのかもしれないです

実際に404エラーを発生させた場合の比較が、下記になります。
Ratpackの404エラーページ有無のほか、ログに独自ハンドラーを定義するよう警告されます。

`development(true)`
![404_1.PNG](https://qiita-image-store.s3.amazonaws.com/0/231669/64c0ed64-6293-502f-103b-0e1ed6572bd0.png)

`19:02:26.231 [ratpack-compute-1-2] ERROR ratpack.error.internal.DefaultDevelopmentErrorHandler - 404 client error for request to /hoge`

`development(false)`
![404_2.PNG](https://qiita-image-store.s3.amazonaws.com/0/231669/9d82334b-32ed-efc5-9de1-413c88dc5b04.png)

`19:00:55.861 [ratpack-compute-1-4] WARN ratpack.error.internal.DefaultProductionErrorHandler - Default production error handler used to render client error, please add a ratpack.error.ClientErrorHandler instance to your application (method: GET, uri: /hoge)`

`development(true)`は手軽に使えますが、本番環境では独自の`ErrorHandler`を作成することが推奨されているようです。

エラーハンドラーには`ClientErrorHandler`と`ServerErrorHandler`の二種類があります。

`ClientErrorHandler`は404など、クライアントのリクエストに問題があった時に呼び出されます。
`Context`と`int`ステータスコードを引数にとる`error()`メソッドをオーバーライドします。

`ServerErrorHandler`はハンドラーでエラーが発生したときに呼び出されます。
`Context`と発生した例外を表す`Throwable`を引数にとる`error()`メソッドがあります。
`ServerErrorHandler`はRatpackにおけるエラー処理の最後の砦なので、基本的に例外を投げないことが推奨されています。

ところでこのメソッド、`Exception`ではなく`Throwable`を引数に持っている通り、`Error`が発生した場合も処理されます。
Javaでは一般的に`Error`をキャッチしないことが推奨されていますので、その場合無理に復帰を試みないほうが良いと思われます。


## `Registry`

Ratpackサーバーにモジュールなど部品を登録していくクラスです。今回は何も使わないので、空の実装を使用します。
上記のエラーハンドラーなどは、このレジストリに登録することで利用可能になります。


## handlers

Ratpackは、`Chain`によってまとめられた複数の`Handler`によってルーティングを行います。
`Chain.get(String, Handler)`メソッドは、HTTPのGETリクエストを、引数のハンドラーに結びつけています。
第一引数の文字列はパスです。今回のように省略するとルートにマッピングされます。

`Context.render(Object)`が、レスポンスのボディーを出力するメソッドです。
今回はStringを引数に渡しているので、そのままその文字列が出力されることになりますが、文字列以外のオブジェクトを渡すこともできます。
`render()`は`Registry`に登録された`Renderer`が、型に応じて呼び出され、レスポンスに変換する仕組みになっています。
Stringには(正確にはCharSequenceには)組み込みの`Renderer`があるため、明示的にレンダラーを登録しなくても、`Context.render()`で呼び出せるという仕組みになっています。


```java
RatpackServer.of( spec -> spec.serverConfig( config )
                              .registry( registry )
                              .handlers( handlers ) )
             .start();
```

`of()`メソッドで`ServerConfig`、`Registry`、`Handler`を設定し、`RatpackServer`インスタンスを作成します。
`start()`メソッドでサーバーが起動され、リクエストの受け付けを開始します。

`RatpackServerSpec`の各メソッド(`serverConfig()`、`registry()`、`handler()`および`handlers()`)は、対応するクラスのインスタンスを引数に持つものと、`Action`経由で設定するものなどいろいろあります。
個人的には例に挙げたように、コンフィグとレジストリに関してはインスタンスを、ハンドラーには`Action`を使うのがやりやすい気がします。この辺は主観なのでいろいろ試してみることをお勧めします。