Current section

Files

Jump to
eview lib eview views error_view.ex
Raw

lib/eview/views/error_view.ex

defmodule EView.Views.Error do
@moduledoc """
Views for different kind of 4xx and 5xx error of your application.
"""
@internal_error_templates ["500.json", "501.json", "503.json", "505.json"]
def render(template, assigns \\ %{})
@doc """
Render error for malformed request (for example when Plug.Parser can't parse content type).
"""
def render("400.json", assigns) do
# This bitch don't want to handle before_send
%{
type: :request_malformed,
invalid: [
%{
entry_type: :request,
rules: [
%{rule: :json}
]
}
],
message: "Malformed request. Probably, you have sent corrupted JSON."
}
|> put_type(assigns)
|> put_message(assigns)
end
@doc """
Render access denied error. Can have custom `type` and `invalid` error fields.
For invalid tokens it should look like:
{
meta: {
code: 401
},
error: {
type: :access_denied,
invalid:[{
entry_type: "header",
entry: "Authorization",
rules: [
{rule: "scopes", params:[list_of_scopes_needed]}
]
}]
}
}
"""
def render("401.json", assigns) do
%{type: :access_denied}
|> put_type(assigns)
|> put_invalid(assigns)
|> put_message(assigns)
end
def render("403.json", assigns) do
%{type: :forbidden}
|> put_type(assigns)
|> put_invalid(assigns)
|> put_message(assigns)
end
@doc """
This render will be used by-default for non-existent routes. You can use it in your controller:
conn |> render("404.json", %{type: my_type})
"""
def render("404.json", assigns) do
%{type: :not_found}
|> put_type(assigns)
|> put_message(assigns)
end
def render("406.json", assigns) do
%{
type: :content_type_invalid,
invalid: [
%{
entry_type: :header,
entry: "Accept"
}
],
message: "Accept header is missing or invalid. Try to set 'Accept: application/json' header."
}
|> put_type(assigns)
|> put_message(assigns)
end
@doc """
This render should be used for PUT requests that can not be completed.
"""
def render("409.json", assigns) do
%{
type: :request_conflict,
message: "The request could not be completed due to a conflict with the current state of the resource."
}
|> put_message(assigns)
|> put_type(assigns)
end
def render("413.json", assigns) do
# This bitch don't want to handle before_send
%{
type: :request_too_large,
invalid: [
%{
entry_type: :request,
rules: [
%{rule: :size}
]
}
],
message: "Request body is too large."
}
|> put_type(assigns)
|> put_message(assigns)
end
def render("415.json", assigns) do
# This bitch don't want to handle before_send
%{
type: :content_type_invalid,
invalid: [
%{
entry_type: :header,
entry: "Content-Type"
}
],
message:
"Invalid Content-Type header. Try to set 'Content-Type: application/json' header: " <>
"http://docs.apimanifest.apiary.io/#introduction/interacting-with-api/content-type."
}
|> put_type(assigns)
|> put_message(assigns)
end
def render("424.json", assigns) do
%{
type: :failed_dependency,
message:
"The method could not be performed on the resource because the requested action depended on another " <>
"action and that action failed."
}
|> put_type(assigns)
|> put_message(assigns)
end
@doc """
This render will be used by-default for internal errors. You can use it in your controller:
conn |> render("500.json", %{type: my_type})
"""
def render(template, assigns) when template in @internal_error_templates do
%{type: :internal_error}
|> put_type(assigns)
|> put_message(assigns)
end
defp put_type(body, %{type: type}) when is_atom(type) or is_binary(type) do
body
|> Map.put(:type, type)
end
defp put_type(body, _), do: body
defp put_invalid(body, %{invalid: invalid}) when is_map(invalid) do
body
|> Map.put(:invalid, invalid)
end
defp put_invalid(body, _), do: body
defp put_message(body, %{message: message}) when is_binary(message) do
body
|> Map.put(:message, message)
end
defp put_message(body, _), do: body
end