Merge branch 'develop' into openapi/account
[akkoma] / lib / pleroma / web / api_spec / render_error.ex
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Web.ApiSpec.RenderError do
6 @behaviour Plug
7
8 import Plug.Conn, only: [put_status: 2]
9 import Phoenix.Controller, only: [json: 2]
10 import Pleroma.Web.Gettext
11
12 @impl Plug
13 def init(opts), do: opts
14
15 @impl Plug
16
17 def call(conn, errors) do
18 errors =
19 Enum.map(errors, fn
20 %{name: nil} = err ->
21 %OpenApiSpex.Cast.Error{err | name: List.last(err.path)}
22
23 err ->
24 err
25 end)
26
27 conn
28 |> put_status(:bad_request)
29 |> json(%{
30 error: errors |> Enum.map(&message/1) |> Enum.join(" "),
31 errors: errors |> Enum.map(&render_error/1)
32 })
33 end
34
35 defp render_error(error) do
36 pointer = OpenApiSpex.path_to_string(error)
37
38 %{
39 title: "Invalid value",
40 source: %{
41 pointer: pointer
42 },
43 message: OpenApiSpex.Cast.Error.message(error)
44 }
45 end
46
47 defp message(%{reason: :invalid_schema_type, type: type, name: name}) do
48 gettext("%{name} - Invalid schema.type. Got: %{type}.",
49 name: name,
50 type: inspect(type)
51 )
52 end
53
54 defp message(%{reason: :null_value, name: name} = error) do
55 case error.type do
56 nil ->
57 gettext("%{name} - null value.", name: name)
58
59 type ->
60 gettext("%{name} - null value where %{type} expected.",
61 name: name,
62 type: type
63 )
64 end
65 end
66
67 defp message(%{reason: :all_of, meta: %{invalid_schema: invalid_schema}}) do
68 gettext(
69 "Failed to cast value as %{invalid_schema}. Value must be castable using `allOf` schemas listed.",
70 invalid_schema: invalid_schema
71 )
72 end
73
74 defp message(%{reason: :any_of, meta: %{failed_schemas: failed_schemas}}) do
75 gettext("Failed to cast value using any of: %{failed_schemas}.",
76 failed_schemas: failed_schemas
77 )
78 end
79
80 defp message(%{reason: :one_of, meta: %{failed_schemas: failed_schemas}}) do
81 gettext("Failed to cast value to one of: %{failed_schemas}.", failed_schemas: failed_schemas)
82 end
83
84 defp message(%{reason: :min_length, length: length, name: name}) do
85 gettext("%{name} - String length is smaller than minLength: %{length}.",
86 name: name,
87 length: length
88 )
89 end
90
91 defp message(%{reason: :max_length, length: length, name: name}) do
92 gettext("%{name} - String length is larger than maxLength: %{length}.",
93 name: name,
94 length: length
95 )
96 end
97
98 defp message(%{reason: :unique_items, name: name}) do
99 gettext("%{name} - Array items must be unique.", name: name)
100 end
101
102 defp message(%{reason: :min_items, length: min, value: array, name: name}) do
103 gettext("%{name} - Array length %{length} is smaller than minItems: %{min}.",
104 name: name,
105 length: length(array),
106 min: min
107 )
108 end
109
110 defp message(%{reason: :max_items, length: max, value: array, name: name}) do
111 gettext("%{name} - Array length %{length} is larger than maxItems: %{}.",
112 name: name,
113 length: length(array),
114 max: max
115 )
116 end
117
118 defp message(%{reason: :multiple_of, length: multiple, value: count, name: name}) do
119 gettext("%{name} - %{count} is not a multiple of %{multiple}.",
120 name: name,
121 count: count,
122 multiple: multiple
123 )
124 end
125
126 defp message(%{reason: :exclusive_max, length: max, value: value, name: name})
127 when value >= max do
128 gettext("%{name} - %{value} is larger than exclusive maximum %{max}.",
129 name: name,
130 value: value,
131 max: max
132 )
133 end
134
135 defp message(%{reason: :maximum, length: max, value: value, name: name})
136 when value > max do
137 gettext("%{name} - %{value} is larger than inclusive maximum %{max}.",
138 name: name,
139 value: value,
140 max: max
141 )
142 end
143
144 defp message(%{reason: :exclusive_multiple, length: min, value: value, name: name})
145 when value <= min do
146 gettext("%{name} - %{value} is smaller than exclusive minimum %{min}.",
147 name: name,
148 value: value,
149 min: min
150 )
151 end
152
153 defp message(%{reason: :minimum, length: min, value: value, name: name})
154 when value < min do
155 gettext("%{name} - %{value} is smaller than inclusive minimum %{min}.",
156 name: name,
157 value: value,
158 min: min
159 )
160 end
161
162 defp message(%{reason: :invalid_type, type: type, value: value, name: name}) do
163 gettext("%{name} - Invalid %{type}. Got: %{value}.",
164 name: name,
165 value: OpenApiSpex.TermType.type(value),
166 type: type
167 )
168 end
169
170 defp message(%{reason: :invalid_format, format: format, name: name}) do
171 gettext("%{name} - Invalid format. Expected %{format}.", name: name, format: inspect(format))
172 end
173
174 defp message(%{reason: :invalid_enum, name: name}) do
175 gettext("%{name} - Invalid value for enum.", name: name)
176 end
177
178 defp message(%{reason: :polymorphic_failed, type: polymorphic_type}) do
179 gettext("Failed to cast to any schema in %{polymorphic_type}",
180 polymorphic_type: polymorphic_type
181 )
182 end
183
184 defp message(%{reason: :unexpected_field, name: name}) do
185 gettext("Unexpected field: %{name}.", name: safe_string(name))
186 end
187
188 defp message(%{reason: :no_value_for_discriminator, name: field}) do
189 gettext("Value used as discriminator for `%{field}` matches no schemas.", name: field)
190 end
191
192 defp message(%{reason: :invalid_discriminator_value, name: field}) do
193 gettext("No value provided for required discriminator `%{field}`.", name: field)
194 end
195
196 defp message(%{reason: :unknown_schema, name: name}) do
197 gettext("Unknown schema: %{name}.", name: name)
198 end
199
200 defp message(%{reason: :missing_field, name: name}) do
201 gettext("Missing field: %{name}.", name: name)
202 end
203
204 defp message(%{reason: :missing_header, name: name}) do
205 gettext("Missing header: %{name}.", name: name)
206 end
207
208 defp message(%{reason: :invalid_header, name: name}) do
209 gettext("Invalid value for header: %{name}.", name: name)
210 end
211
212 defp message(%{reason: :max_properties, meta: meta}) do
213 gettext(
214 "Object property count %{property_count} is greater than maxProperties: %{max_properties}.",
215 property_count: meta.property_count,
216 max_properties: meta.max_properties
217 )
218 end
219
220 defp message(%{reason: :min_properties, meta: meta}) do
221 gettext(
222 "Object property count %{property_count} is less than minProperties: %{min_properties}",
223 property_count: meta.property_count,
224 min_properties: meta.min_properties
225 )
226 end
227
228 defp safe_string(string) do
229 to_string(string) |> String.slice(0..39)
230 end
231 end