/
error_view.ex
181 lines (160 loc) · 4.41 KB
/
error_view.ex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
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