Blog

sprayのRejectionHandlerで遊んでみた


こんにちは。Dynalystのkayanoです。

Dynalystでは、管理画面などで利用するAPIにsprayを使っています。

今日は、そのAPIの開発で
RejectionHandlerを使ってエラーのハンドリングをしていて便利だったので、ちょっと遊んでみました。

sprayのRejection

sprayでは、リクエストのpathや、paramaterなどがroutingに合わなかった場合にRejectionが呼ばれます。
例えば、CookieDirectivesの実装では、Cookieが無かった場合に、MissingCookieRejectionがrejectされます。

routingでcompleteされなかったリクエストは、rejectされたRejectionの型によってレスポンスが決まります。
そのレスポンスをハンドリングしているのがRejectionHandlerです。

defaultのRejectionHandler

sprayでrejectされると、特に何も設定していなければ、defaultのRejectionHandlerが働きます。

※ defaultの内容

https://github.com/spray/spray/blob/master/spray-routing/src/main/scala/spray/routing/RejectionHandler.scala

例えばこんなActorを用意したとします。

sbtで起動してcurlでリクエストしてみます。

parameterが正常な場合

parameterが不正な場合

sprayでparameterの不正でrejectionされた場合は、MalformedQueryParamRejectionというRejectionでrejectされます。rejestされたリクエストがどのように処理されるかはRejectionHandlerによって決まります。

Defaultで設定されているRejectionHandlerのMalformedQueryParamRejectionでは

この様に設定されているため、上記の様にテストするとtextでエラーメッセージが飛ぶのですね。

RejectionHandlerをカスタマイズしてみる

さて、基本的にAPIのIFは合わせたいので、jsonを扱っているAPIであれば、利用する側のことも考えてエラー時もJsonを返したいところです。さっきの例でrouteに普通に追加して処理することもできますが

見辛いし、なによりメンテナンス性に欠けます。やりたくない。テンション下がる。。。

これをRejectionHandlerで処理してみます。

このようにRejectionHandlerをimplicitで定義するだけです。簡単ですね。
※ sprayでのjsonの扱いはもっとイケてる方法がありますが、それはまた次の機会にします。

実行してみます

エラーがjsonで返る様になりました

Rejectionを作ってみる

もう少しカスタマイズしてみます。今度は自分でRejectionを作ってみます。Cookieの値に関するRejectionがみつからなかったので、作ってみました。

ベタな感じですが、”mycookie”というcookieを取得し、cookieの値が”my”で始まらなかったらrejectionを飛ばすしてみます。

独自で作ったRejectionを受け取る様にHandlerを定義します。

cookie自体が無かった時に起きるMissingCookieRejectionも忘れずに定義します。

実行してみます。
成功パターン

cookieのvalueが不正なパターン

cookieがないパターン

Rejectionの使いどころ

多機能なAPIを開発していると、複数のrouteを結合して利用する事が多くなります。元々私がRejectionに触れたは、後続のrouteで処理したい内容が、その前のrouteの定義内でエラーとしてcompleteしてしまうと、後続サービスが機能しなくなってしまう問題を解決させたいのが発端でした。

他の機能に影響しない様にするため、また全体のIFを統一化のためにも、基本的には異常時の処理は、completeではなくrejectを行った方がよいと思いました。あと、定義されてるRejectionはいろんな処理があって、眺めてて面白かったので、Spray でRestAPIを作る際などはぜひ見てみてください。

※ 今回試してみたコードはこちらです。
https://github.com/kayano-shoko/spray-test

それでは、また。

Author

アバター
shoko