Phoenix 1.3 では action_fallback
が追加されたためエラーハンドリングがとても簡単になりました。
http://phoenixframework.org/blog/phoenix-1-3-0-released
しかし、Phoenix.Router.NoRouteError
が発生した場合にはコントローラーまで処理が届かないため、 action_fallback
は使用できません。
そこで、 Plug.ErrorHandler
を使用して NoRouteError に対応してみようと思います。
まず、以下のような ErrorView を作成します。
# views/error_view.ex
defmodule HelloWeb.ErrorView do
use HelloWeb, :view
def render("404.json", _assigns) do
%{errors: %{detail: "Page not found"}}
end
def render("500.json", _assigns) do
%{errors: %{detail: "Internal server error"}}
end
def render(_template, assigns) do
render "500.json", assigns
end
end
次に、 Plug.ErrorHandler.handle_errors
をオーバーライドするモジュールを定義します。
# router_error_handling.ex
defmodule HelloWeb.RouterErrorHandling do
defmacro __using__(_) do
quote do
use Plug.ErrorHandler
def handle_errors(conn, %{reason: reason} = %{reason: %Phoenix.Router.NoRouteError{}}) do
send_resp(conn, conn.status, Poison.encode!(HelloWeb.ErrorView.render("#{reason.plug_status}.json", %{})))
end
def handle_errors(conn, %{kind: _kind, reason: _reason, stack: _stack}) do
send_resp(conn, conn.status, Poison.encode!(HelloWeb.ErrorView.render("500.json", %{})))
end
end
end
end
最後に上記モジュールを Router 内で use して終わりです。
# router.ex
defmodule HelloWeb.Router do
use HelloWeb, :router
use HelloWeb.RouterErrorHandling
...
end
独自実装の use 反対派の宗教に入っている方は RouterErrorHandling を定義せずに Router 内で直接 Plug.ErrorHandler を use して handle_errors を書く感じでも動作はしました。
私の場合は、 Router にルーティング定義以外の処理を書いてルーティングの見通しが悪くなるのが嫌だったので別モジュールにしています。
Poison.encode!(HelloWeb.ErrorView.render("#{reason.plug_status}.json", %{}))
に気持ち悪さを感じるので、この辺いい感じにしたい......。
Top comments (0)