博多南ウェブサービスのblog

博多南ウェブサービスのサービス紹介

【Play Framework 3.0.x サンプル】レスポンスエラーコードの表示画面を変更したい

Play Framework 3.0.x (以下、Play) を始めたばかりの方向けに、サンプルを進めるうえで困ったところを共有する目的で書いています。

Play にて、エラーレスポンス(クライアント、サーバー)の表示画面を、変更したときのメモです。

以下、目次

背景

ドキュメント にあるとおり、Play では、

  • リクエストに対して、自動的にclient error を検出する
  • アプリでの例外スローに対して、自動的にserver error を処理する

そして、エラーページを生成する。

また、別のドキュメント にあるとおり、Play では、

  • 明示的な(つまり、Action としての)、NotFoundInternalServerError に対して、エラーページは生成せずに該当するエラーステータスを返す

方針

  • エラーレスポンス(クライアント、サーバー)を返す際に、ほかのページと統一感のある(つまり、ヘッダー、フッター、メニュー部分が共通の)ページを表示する
  • (可能なら)明示的なNotFound についても、ドキュメント にある、onClientError, onServerError を利用する

結果

ほかのページと統一感のあるページを表示する

自動生成のエラーページ => 独自のエラーページ に変更した。

これには、ドキュメントにあるとおり、 DefaultHttpErrorHandler を拡張する か、 HttpErrorHandler を実装する かで、実現できた。

どちらを使えばよいかは、ドキュメントを見ても理解できていない。

ので、判断基準として、書きやすい(または、コードを見たときに一覧性がある)もを選んだ(HttpErrorHandler を実装した。)

onClientError, onServerError を明示的なNotFound 等にも利用する

Action.async { Future.successful(...) } (のようなもの)に対して、NotFound 等を指定しているところに、HttpErrorHandler を呼び出す処理に変更した。

これは、なにがしたかったのかというと、

  • HttpErrorHandler を実装する」では、route が定義されていないパスにアクセスがあったときは、実装したerror handler が呼び出される
  • HttpErrorHandler を実装する」では、NotFound Action を明示的に指定したときは(つまり、route を定義しておいて、NotFound を返すときは)、実装したerror handler が呼び出されない

となっているものを、どちらも同じ処理にしたかったというもの。

具体的には、

class TestController @Inject() (
    (省略)
    mcc: MessagesControllerComponents
)(implicit
    (省略)
) extends MessagesAbstractController(mcc) {

  def test =
    Action.async { implicit request: Request[AnyContent] =>
      play.api.mvc.Results.NotFound("レスポンス 404")
    }
}

のような、NotFound を返している(これが、良いかどうかはわからない)個所を、

class TestController @Inject() (
    (省略)
    mcc: MessagesControllerComponents,
+    errorHandler: ErrorHandler
)(implicit
    (省略)
) extends MessagesAbstractController(mcc) {

  def test =
    Action.async { implicit request: Request[AnyContent] =>
-      play.api.mvc.Results.NotFound("レスポンス 404")
+      errorHandler.onClientError(request, 404, "レスポンス 404")
    }
}

のように、onClientError を呼び出すようにした

できてないところ

そもそも、Action として、NotFound, InternalServerError 等を返す設計が良いかの判断ができていない。 ただ、play.api.mvc.Results.NotFound() を用意しているということは、 そのような設計も想定しているのだろうけど。

参考にしたところ

以上でした。