sanger-jsonapi-resources 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +53 -0
- data/lib/generators/jsonapi/USAGE +13 -0
- data/lib/generators/jsonapi/controller_generator.rb +14 -0
- data/lib/generators/jsonapi/resource_generator.rb +14 -0
- data/lib/generators/jsonapi/templates/jsonapi_controller.rb +4 -0
- data/lib/generators/jsonapi/templates/jsonapi_resource.rb +4 -0
- data/lib/jsonapi/acts_as_resource_controller.rb +320 -0
- data/lib/jsonapi/cached_resource_fragment.rb +127 -0
- data/lib/jsonapi/callbacks.rb +51 -0
- data/lib/jsonapi/compiled_json.rb +36 -0
- data/lib/jsonapi/configuration.rb +258 -0
- data/lib/jsonapi/error.rb +47 -0
- data/lib/jsonapi/error_codes.rb +60 -0
- data/lib/jsonapi/exceptions.rb +563 -0
- data/lib/jsonapi/formatter.rb +169 -0
- data/lib/jsonapi/include_directives.rb +100 -0
- data/lib/jsonapi/link_builder.rb +152 -0
- data/lib/jsonapi/mime_types.rb +41 -0
- data/lib/jsonapi/naive_cache.rb +30 -0
- data/lib/jsonapi/operation.rb +24 -0
- data/lib/jsonapi/operation_dispatcher.rb +88 -0
- data/lib/jsonapi/operation_result.rb +65 -0
- data/lib/jsonapi/operation_results.rb +35 -0
- data/lib/jsonapi/paginator.rb +209 -0
- data/lib/jsonapi/processor.rb +328 -0
- data/lib/jsonapi/relationship.rb +94 -0
- data/lib/jsonapi/relationship_builder.rb +167 -0
- data/lib/jsonapi/request_parser.rb +678 -0
- data/lib/jsonapi/resource.rb +1255 -0
- data/lib/jsonapi/resource_controller.rb +5 -0
- data/lib/jsonapi/resource_controller_metal.rb +16 -0
- data/lib/jsonapi/resource_serializer.rb +531 -0
- data/lib/jsonapi/resources/version.rb +5 -0
- data/lib/jsonapi/response_document.rb +135 -0
- data/lib/jsonapi/routing_ext.rb +262 -0
- data/lib/jsonapi-resources.rb +27 -0
- metadata +223 -0
@@ -0,0 +1,563 @@
|
|
1
|
+
module JSONAPI
|
2
|
+
module Exceptions
|
3
|
+
class Error < RuntimeError
|
4
|
+
attr :error_object_overrides
|
5
|
+
|
6
|
+
def initialize(error_object_overrides = {})
|
7
|
+
@error_object_overrides = error_object_overrides
|
8
|
+
end
|
9
|
+
|
10
|
+
def create_error_object(error_defaults)
|
11
|
+
JSONAPI::Error.new(error_defaults.merge(error_object_overrides))
|
12
|
+
end
|
13
|
+
|
14
|
+
def errors
|
15
|
+
# :nocov:
|
16
|
+
raise NotImplementedError, "Subclass of Error must implement errors method"
|
17
|
+
# :nocov:
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class InternalServerError < Error
|
22
|
+
attr_accessor :exception
|
23
|
+
|
24
|
+
def initialize(exception, error_object_overrides = {})
|
25
|
+
@exception = exception
|
26
|
+
super(error_object_overrides)
|
27
|
+
end
|
28
|
+
|
29
|
+
def errors
|
30
|
+
if JSONAPI.configuration.include_backtraces_in_errors
|
31
|
+
meta = Hash.new
|
32
|
+
meta[:exception] = exception.message
|
33
|
+
meta[:backtrace] = exception.backtrace
|
34
|
+
end
|
35
|
+
|
36
|
+
[create_error_object(code: JSONAPI::INTERNAL_SERVER_ERROR,
|
37
|
+
status: :internal_server_error,
|
38
|
+
title: I18n.t('jsonapi-resources.exceptions.internal_server_error.title',
|
39
|
+
default: 'Internal Server Error'),
|
40
|
+
detail: I18n.t('jsonapi-resources.exceptions.internal_server_error.detail',
|
41
|
+
default: 'Internal Server Error'),
|
42
|
+
meta: meta)]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class InvalidResource < Error
|
47
|
+
attr_accessor :resource
|
48
|
+
|
49
|
+
def initialize(resource, error_object_overrides = {})
|
50
|
+
@resource = resource
|
51
|
+
super(error_object_overrides)
|
52
|
+
end
|
53
|
+
|
54
|
+
def errors
|
55
|
+
[create_error_object(code: JSONAPI::INVALID_RESOURCE,
|
56
|
+
status: :bad_request,
|
57
|
+
title: I18n.t('jsonapi-resources.exceptions.invalid_resource.title',
|
58
|
+
default: 'Invalid resource'),
|
59
|
+
detail: I18n.t('jsonapi-resources.exceptions.invalid_resource.detail',
|
60
|
+
default: "#{resource} is not a valid resource.", resource: resource))]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
class RecordNotFound < Error
|
65
|
+
attr_accessor :id
|
66
|
+
|
67
|
+
def initialize(id, error_object_overrides = {})
|
68
|
+
@id = id
|
69
|
+
super(error_object_overrides)
|
70
|
+
end
|
71
|
+
|
72
|
+
def errors
|
73
|
+
[create_error_object(code: JSONAPI::RECORD_NOT_FOUND,
|
74
|
+
status: :not_found,
|
75
|
+
title: I18n.translate('jsonapi-resources.exceptions.record_not_found.title',
|
76
|
+
default: 'Record not found'),
|
77
|
+
detail: I18n.translate('jsonapi-resources.exceptions.record_not_found.detail',
|
78
|
+
default: "The record identified by #{id} could not be found.", id: id))]
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
class UnsupportedMediaTypeError < Error
|
83
|
+
attr_accessor :media_type
|
84
|
+
|
85
|
+
def initialize(media_type, error_object_overrides = {})
|
86
|
+
@media_type = media_type
|
87
|
+
super(error_object_overrides)
|
88
|
+
end
|
89
|
+
|
90
|
+
def errors
|
91
|
+
[create_error_object(code: JSONAPI::UNSUPPORTED_MEDIA_TYPE,
|
92
|
+
status: :unsupported_media_type,
|
93
|
+
title: I18n.translate('jsonapi-resources.exceptions.unsupported_media_type.title',
|
94
|
+
default: 'Unsupported media type'),
|
95
|
+
detail: I18n.translate('jsonapi-resources.exceptions.unsupported_media_type.detail',
|
96
|
+
default: "All requests that create or update must use the '#{JSONAPI::MEDIA_TYPE}' Content-Type. This request specified '#{media_type}'.",
|
97
|
+
needed_media_type: JSONAPI::MEDIA_TYPE,
|
98
|
+
media_type: media_type))]
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
class NotAcceptableError < Error
|
103
|
+
attr_accessor :media_type
|
104
|
+
|
105
|
+
def initialize(media_type, error_object_overrides = {})
|
106
|
+
@media_type = media_type
|
107
|
+
super(error_object_overrides)
|
108
|
+
end
|
109
|
+
|
110
|
+
def errors
|
111
|
+
[create_error_object(code: JSONAPI::NOT_ACCEPTABLE,
|
112
|
+
status: :not_acceptable,
|
113
|
+
title: I18n.translate('jsonapi-resources.exceptions.not_acceptable.title',
|
114
|
+
default: 'Not acceptable'),
|
115
|
+
detail: I18n.translate('jsonapi-resources.exceptions.not_acceptable.detail',
|
116
|
+
default: "All requests must use the '#{JSONAPI::MEDIA_TYPE}' Accept without media type parameters. This request specified '#{media_type}'.",
|
117
|
+
needed_media_type: JSONAPI::MEDIA_TYPE,
|
118
|
+
media_type: media_type))]
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
|
123
|
+
class HasManyRelationExists < Error
|
124
|
+
attr_accessor :id
|
125
|
+
|
126
|
+
def initialize(id, error_object_overrides = {})
|
127
|
+
@id = id
|
128
|
+
super(error_object_overrides)
|
129
|
+
end
|
130
|
+
|
131
|
+
def errors
|
132
|
+
[create_error_object(code: JSONAPI::RELATION_EXISTS,
|
133
|
+
status: :bad_request,
|
134
|
+
title: I18n.translate('jsonapi-resources.exceptions.has_many_relation.title',
|
135
|
+
default: 'Relation exists'),
|
136
|
+
detail: I18n.translate('jsonapi-resources.exceptions.has_many_relation.detail',
|
137
|
+
default: "The relation to #{id} already exists.",
|
138
|
+
id: id))]
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
class BadRequest < Error
|
143
|
+
def initialize(exception)
|
144
|
+
@exception = exception
|
145
|
+
end
|
146
|
+
|
147
|
+
def errors
|
148
|
+
[JSONAPI::Error.new(code: JSONAPI::BAD_REQUEST,
|
149
|
+
status: :bad_request,
|
150
|
+
title: I18n.translate('jsonapi-resources.exceptions.bad_request.title',
|
151
|
+
default: 'Bad Request'),
|
152
|
+
detail: I18n.translate('jsonapi-resources.exceptions.bad_request.detail',
|
153
|
+
default: @exception))]
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
class InvalidRequestFormat < Error
|
158
|
+
def errors
|
159
|
+
[JSONAPI::Error.new(code: JSONAPI::BAD_REQUEST,
|
160
|
+
status: :bad_request,
|
161
|
+
title: I18n.translate('jsonapi-resources.exceptions.invalid_request_format.title',
|
162
|
+
default: 'Bad Request'),
|
163
|
+
detail: I18n.translate('jsonapi-resources.exceptions.invalid_request_format.detail',
|
164
|
+
default: 'Request must be a hash'))]
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
class ToManySetReplacementForbidden < Error
|
169
|
+
def errors
|
170
|
+
[create_error_object(code: JSONAPI::FORBIDDEN,
|
171
|
+
status: :forbidden,
|
172
|
+
title: I18n.translate('jsonapi-resources.exceptions.to_many_set_replacement_forbidden.title',
|
173
|
+
default: 'Complete replacement forbidden'),
|
174
|
+
detail: I18n.translate('jsonapi-resources.exceptions.to_many_set_replacement_forbidden.detail',
|
175
|
+
default: 'Complete replacement forbidden for this relationship'))]
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
class InvalidFiltersSyntax < Error
|
180
|
+
attr_accessor :filters
|
181
|
+
|
182
|
+
def initialize(filters, error_object_overrides = {})
|
183
|
+
@filters = filters
|
184
|
+
super(error_object_overrides)
|
185
|
+
end
|
186
|
+
|
187
|
+
def errors
|
188
|
+
[create_error_object(code: JSONAPI::INVALID_FILTERS_SYNTAX,
|
189
|
+
status: :bad_request,
|
190
|
+
title: I18n.translate('jsonapi-resources.exceptions.invalid_filter_syntax.title',
|
191
|
+
default: 'Invalid filters syntax'),
|
192
|
+
detail: I18n.translate('jsonapi-resources.exceptions.invalid_filter_syntax.detail',
|
193
|
+
default: "#{filters} is not a valid syntax for filtering.",
|
194
|
+
filters: filters))]
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
class FilterNotAllowed < Error
|
199
|
+
attr_accessor :filter
|
200
|
+
|
201
|
+
def initialize(filter, error_object_overrides = {})
|
202
|
+
@filter = filter
|
203
|
+
super(error_object_overrides)
|
204
|
+
end
|
205
|
+
|
206
|
+
def errors
|
207
|
+
[create_error_object(code: JSONAPI::FILTER_NOT_ALLOWED,
|
208
|
+
status: :bad_request,
|
209
|
+
title: I18n.translate('jsonapi-resources.exceptions.filter_not_allowed.title',
|
210
|
+
default: 'Filter not allowed'),
|
211
|
+
detail: I18n.translate('jsonapi-resources.exceptions.filter_not_allowed.detail',
|
212
|
+
default: "#{filter} is not allowed.", filter: filter))]
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
class InvalidFilterValue < Error
|
217
|
+
attr_accessor :filter, :value
|
218
|
+
|
219
|
+
def initialize(filter, value, error_object_overrides = {})
|
220
|
+
@filter = filter
|
221
|
+
@value = value
|
222
|
+
super(error_object_overrides)
|
223
|
+
end
|
224
|
+
|
225
|
+
def errors
|
226
|
+
[create_error_object(code: JSONAPI::INVALID_FILTER_VALUE,
|
227
|
+
status: :bad_request,
|
228
|
+
title: I18n.translate('jsonapi-resources.exceptions.invalid_filter_value.title',
|
229
|
+
default: 'Invalid filter value'),
|
230
|
+
detail: I18n.translate('jsonapi-resources.exceptions.invalid_filter_value.detail',
|
231
|
+
default: "#{value} is not a valid value for #{filter}.",
|
232
|
+
value: value, filter: filter))]
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
class InvalidFieldValue < Error
|
237
|
+
attr_accessor :field, :value
|
238
|
+
|
239
|
+
def initialize(field, value, error_object_overrides = {})
|
240
|
+
@field = field
|
241
|
+
@value = value
|
242
|
+
super(error_object_overrides)
|
243
|
+
end
|
244
|
+
|
245
|
+
def errors
|
246
|
+
[create_error_object(code: JSONAPI::INVALID_FIELD_VALUE,
|
247
|
+
status: :bad_request,
|
248
|
+
title: I18n.translate('jsonapi-resources.exceptions.invalid_field_value.title',
|
249
|
+
default: 'Invalid field value'),
|
250
|
+
detail: I18n.translate('jsonapi-resources.exceptions.invalid_field_value.detail',
|
251
|
+
default: "#{value} is not a valid value for #{field}.",
|
252
|
+
value: value, field: field))]
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
class InvalidFieldFormat < Error
|
257
|
+
def errors
|
258
|
+
[create_error_object(code: JSONAPI::INVALID_FIELD_FORMAT,
|
259
|
+
status: :bad_request,
|
260
|
+
title: I18n.translate('jsonapi-resources.exceptions.invalid_field_format.title',
|
261
|
+
default: 'Invalid field format'),
|
262
|
+
detail: I18n.translate('jsonapi-resources.exceptions.invalid_field_format.detail',
|
263
|
+
default: 'Fields must specify a type.'))]
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
class InvalidDataFormat < Error
|
268
|
+
def errors
|
269
|
+
[create_error_object(code: JSONAPI::INVALID_DATA_FORMAT,
|
270
|
+
status: :bad_request,
|
271
|
+
title: I18n.translate('jsonapi-resources.exceptions.invalid_data_format.title',
|
272
|
+
default: 'Invalid data format'),
|
273
|
+
detail: I18n.translate('jsonapi-resources.exceptions.invalid_data_format.detail',
|
274
|
+
default: 'Data must be a hash.'))]
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
class InvalidLinksObject < Error
|
279
|
+
def errors
|
280
|
+
[create_error_object(code: JSONAPI::INVALID_LINKS_OBJECT,
|
281
|
+
status: :bad_request,
|
282
|
+
title: I18n.translate('jsonapi-resources.exceptions.invalid_links_object.title',
|
283
|
+
default: 'Invalid Links Object'),
|
284
|
+
detail: I18n.translate('jsonapi-resources.exceptions.invalid_links_object.detail',
|
285
|
+
default: 'Data is not a valid Links Object.'))]
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
class TypeMismatch < Error
|
290
|
+
attr_accessor :type
|
291
|
+
|
292
|
+
def initialize(type, error_object_overrides = {})
|
293
|
+
@type = type
|
294
|
+
super(error_object_overrides)
|
295
|
+
end
|
296
|
+
|
297
|
+
def errors
|
298
|
+
[create_error_object(code: JSONAPI::TYPE_MISMATCH,
|
299
|
+
status: :bad_request,
|
300
|
+
title: I18n.translate('jsonapi-resources.exceptions.type_mismatch.title',
|
301
|
+
default: 'Type Mismatch'),
|
302
|
+
detail: I18n.translate('jsonapi-resources.exceptions.type_mismatch.detail',
|
303
|
+
default: "#{type} is not a valid type for this operation.", type: type))]
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
class InvalidField < Error
|
308
|
+
attr_accessor :field, :type
|
309
|
+
|
310
|
+
def initialize(type, field, error_object_overrides = {})
|
311
|
+
@field = field
|
312
|
+
@type = type
|
313
|
+
super(error_object_overrides)
|
314
|
+
end
|
315
|
+
|
316
|
+
def errors
|
317
|
+
[create_error_object(code: JSONAPI::INVALID_FIELD,
|
318
|
+
status: :bad_request,
|
319
|
+
title: I18n.translate('jsonapi-resources.exceptions.invalid_field.title',
|
320
|
+
default: 'Invalid field'),
|
321
|
+
detail: I18n.translate('jsonapi-resources.exceptions.invalid_field.detail',
|
322
|
+
default: "#{field} is not a valid field for #{type}.",
|
323
|
+
field: field, type: type))]
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
class InvalidInclude < Error
|
328
|
+
attr_accessor :relationship, :resource
|
329
|
+
|
330
|
+
def initialize(resource, relationship, error_object_overrides = {})
|
331
|
+
@resource = resource
|
332
|
+
@relationship = relationship
|
333
|
+
super(error_object_overrides)
|
334
|
+
end
|
335
|
+
|
336
|
+
def errors
|
337
|
+
[create_error_object(code: JSONAPI::INVALID_INCLUDE,
|
338
|
+
status: :bad_request,
|
339
|
+
title: I18n.translate('jsonapi-resources.exceptions.invalid_include.title',
|
340
|
+
default: 'Invalid field'),
|
341
|
+
detail: I18n.translate('jsonapi-resources.exceptions.invalid_include.detail',
|
342
|
+
default: "#{relationship} is not a valid relationship of #{resource}",
|
343
|
+
relationship: relationship, resource: resource))]
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
class InvalidSortCriteria < Error
|
348
|
+
attr_accessor :sort_criteria, :resource
|
349
|
+
|
350
|
+
def initialize(resource, sort_criteria, error_object_overrides = {})
|
351
|
+
@resource = resource
|
352
|
+
@sort_criteria = sort_criteria
|
353
|
+
super(error_object_overrides)
|
354
|
+
end
|
355
|
+
|
356
|
+
def errors
|
357
|
+
[create_error_object(code: JSONAPI::INVALID_SORT_CRITERIA,
|
358
|
+
status: :bad_request,
|
359
|
+
title: I18n.translate('jsonapi-resources.exceptions.invalid_sort_criteria.title',
|
360
|
+
default: 'Invalid sort criteria'),
|
361
|
+
detail: I18n.translate('jsonapi-resources.exceptions.invalid_sort_criteria.detail',
|
362
|
+
default: "#{sort_criteria} is not a valid sort criteria for #{resource}",
|
363
|
+
sort_criteria: sort_criteria, resource: resource))]
|
364
|
+
end
|
365
|
+
end
|
366
|
+
|
367
|
+
class ParametersNotAllowed < Error
|
368
|
+
attr_accessor :params
|
369
|
+
|
370
|
+
def initialize(params, error_object_overrides = {})
|
371
|
+
@params = params
|
372
|
+
super(error_object_overrides)
|
373
|
+
end
|
374
|
+
|
375
|
+
def errors
|
376
|
+
params.collect do |param|
|
377
|
+
create_error_object(code: JSONAPI::PARAM_NOT_ALLOWED,
|
378
|
+
status: :bad_request,
|
379
|
+
title: I18n.translate('jsonapi-resources.exceptions.parameters_not_allowed.title',
|
380
|
+
default: 'Param not allowed'),
|
381
|
+
detail: I18n.translate('jsonapi-resources.exceptions.parameters_not_allowed.detail',
|
382
|
+
default: "#{param} is not allowed.", param: param))
|
383
|
+
|
384
|
+
end
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
class ParameterMissing < Error
|
389
|
+
attr_accessor :param
|
390
|
+
|
391
|
+
def initialize(param, error_object_overrides = {})
|
392
|
+
@param = param
|
393
|
+
super(error_object_overrides)
|
394
|
+
end
|
395
|
+
|
396
|
+
def errors
|
397
|
+
[create_error_object(code: JSONAPI::PARAM_MISSING,
|
398
|
+
status: :bad_request,
|
399
|
+
title: I18n.translate('jsonapi-resources.exceptions.parameter_missing.title',
|
400
|
+
default: 'Missing Parameter'),
|
401
|
+
detail: I18n.translate('jsonapi-resources.exceptions.parameter_missing.detail',
|
402
|
+
default: "The required parameter, #{param}, is missing.", param: param))]
|
403
|
+
end
|
404
|
+
end
|
405
|
+
|
406
|
+
class KeyNotIncludedInURL < Error
|
407
|
+
attr_accessor :key
|
408
|
+
|
409
|
+
def initialize(key, error_object_overrides = {})
|
410
|
+
@key = key
|
411
|
+
super(error_object_overrides)
|
412
|
+
end
|
413
|
+
|
414
|
+
def errors
|
415
|
+
[create_error_object(code: JSONAPI::KEY_NOT_INCLUDED_IN_URL,
|
416
|
+
status: :bad_request,
|
417
|
+
title: I18n.translate('jsonapi-resources.exceptions.key_not_included_in_url.title',
|
418
|
+
default: 'Key is not included in URL'),
|
419
|
+
detail: I18n.translate('jsonapi-resources.exceptions.key_not_included_in_url.detail',
|
420
|
+
default: "The URL does not support the key #{key}",
|
421
|
+
key: key))]
|
422
|
+
end
|
423
|
+
end
|
424
|
+
|
425
|
+
class MissingKey < Error
|
426
|
+
def errors
|
427
|
+
[create_error_object(code: JSONAPI::KEY_ORDER_MISMATCH,
|
428
|
+
status: :bad_request,
|
429
|
+
title: I18n.translate('jsonapi-resources.exceptions.missing_key.title',
|
430
|
+
default: 'A key is required'),
|
431
|
+
detail: I18n.translate('jsonapi-resources.exceptions.missing_key.detail',
|
432
|
+
default: 'The resource object does not contain a key.'))]
|
433
|
+
end
|
434
|
+
end
|
435
|
+
|
436
|
+
class RecordLocked < Error
|
437
|
+
attr_accessor :message
|
438
|
+
|
439
|
+
def initialize(message, error_object_overrides = {})
|
440
|
+
@message = message
|
441
|
+
super(error_object_overrides)
|
442
|
+
end
|
443
|
+
|
444
|
+
def errors
|
445
|
+
[create_error_object(code: JSONAPI::LOCKED,
|
446
|
+
status: :locked,
|
447
|
+
title: I18n.translate('jsonapi-resources.exceptions.record_locked.title',
|
448
|
+
default: 'Locked resource'),
|
449
|
+
detail: "#{message}")]
|
450
|
+
end
|
451
|
+
end
|
452
|
+
|
453
|
+
class ValidationErrors < Error
|
454
|
+
attr_reader :error_messages, :error_metadata, :resource_relationships
|
455
|
+
|
456
|
+
def initialize(resource, error_object_overrides = {})
|
457
|
+
@error_messages = resource.model_error_messages
|
458
|
+
@error_metadata = resource.validation_error_metadata
|
459
|
+
@resource_relationships = resource.class._relationships.keys
|
460
|
+
@key_formatter = JSONAPI.configuration.key_formatter
|
461
|
+
super(error_object_overrides)
|
462
|
+
end
|
463
|
+
|
464
|
+
def format_key(key)
|
465
|
+
@key_formatter.format(key)
|
466
|
+
end
|
467
|
+
|
468
|
+
def errors
|
469
|
+
error_messages.flat_map do |attr_key, messages|
|
470
|
+
messages.map { |message| json_api_error(attr_key, message) }
|
471
|
+
end
|
472
|
+
end
|
473
|
+
|
474
|
+
private
|
475
|
+
|
476
|
+
def json_api_error(attr_key, message)
|
477
|
+
create_error_object(code: JSONAPI::VALIDATION_ERROR,
|
478
|
+
status: :unprocessable_entity,
|
479
|
+
title: message,
|
480
|
+
detail: "#{format_key(attr_key)} - #{message}",
|
481
|
+
source: { pointer: pointer(attr_key) },
|
482
|
+
meta: metadata_for(attr_key, message))
|
483
|
+
end
|
484
|
+
|
485
|
+
def metadata_for(attr_key, message)
|
486
|
+
return if error_metadata.nil?
|
487
|
+
error_metadata[attr_key] ? error_metadata[attr_key][message] : nil
|
488
|
+
end
|
489
|
+
|
490
|
+
def pointer(attr_or_relationship_name)
|
491
|
+
formatted_attr_or_relationship_name = format_key(attr_or_relationship_name)
|
492
|
+
if resource_relationships.include?(attr_or_relationship_name)
|
493
|
+
"/data/relationships/#{formatted_attr_or_relationship_name}"
|
494
|
+
else
|
495
|
+
"/data/attributes/#{formatted_attr_or_relationship_name}"
|
496
|
+
end
|
497
|
+
end
|
498
|
+
end
|
499
|
+
|
500
|
+
class SaveFailed < Error
|
501
|
+
def errors
|
502
|
+
[create_error_object(code: JSONAPI::SAVE_FAILED,
|
503
|
+
status: :unprocessable_entity,
|
504
|
+
title: I18n.translate('jsonapi-resources.exceptions.save_failed.title',
|
505
|
+
default: 'Save failed or was cancelled'),
|
506
|
+
detail: I18n.translate('jsonapi-resources.exceptions.save_failed.detail',
|
507
|
+
default: 'Save failed or was cancelled'))]
|
508
|
+
end
|
509
|
+
end
|
510
|
+
|
511
|
+
class InvalidPageObject < Error
|
512
|
+
def errors
|
513
|
+
[create_error_object(code: JSONAPI::INVALID_PAGE_OBJECT,
|
514
|
+
status: :bad_request,
|
515
|
+
title: I18n.translate('jsonapi-resources.exceptions.invalid_page_object.title',
|
516
|
+
default: 'Invalid Page Object'),
|
517
|
+
detail: I18n.translate('jsonapi-resources.exceptions.invalid_page_object.detail',
|
518
|
+
default: 'Invalid Page Object.'))]
|
519
|
+
end
|
520
|
+
end
|
521
|
+
|
522
|
+
class PageParametersNotAllowed < Error
|
523
|
+
attr_accessor :params
|
524
|
+
|
525
|
+
def initialize(params, error_object_overrides = {})
|
526
|
+
@params = params
|
527
|
+
super(error_object_overrides)
|
528
|
+
end
|
529
|
+
|
530
|
+
def errors
|
531
|
+
params.collect do |param|
|
532
|
+
create_error_object(code: JSONAPI::PARAM_NOT_ALLOWED,
|
533
|
+
status: :bad_request,
|
534
|
+
title: I18n.translate('jsonapi-resources.exceptions.page_parameters_not_allowed.title',
|
535
|
+
default: 'Page parameter not allowed'),
|
536
|
+
detail: I18n.translate('jsonapi-resources.exceptions.page_parameters_not_allowed.detail',
|
537
|
+
default: "#{param} is not an allowed page parameter.",
|
538
|
+
param: param))
|
539
|
+
end
|
540
|
+
end
|
541
|
+
end
|
542
|
+
|
543
|
+
class InvalidPageValue < Error
|
544
|
+
attr_accessor :page, :value
|
545
|
+
|
546
|
+
def initialize(page, value, error_object_overrides = {})
|
547
|
+
@page = page
|
548
|
+
@value = value
|
549
|
+
super(error_object_overrides)
|
550
|
+
end
|
551
|
+
|
552
|
+
def errors
|
553
|
+
[create_error_object(code: JSONAPI::INVALID_PAGE_VALUE,
|
554
|
+
status: :bad_request,
|
555
|
+
title: I18n.translate('jsonapi-resources.exceptions.invalid_page_value.title',
|
556
|
+
default: 'Invalid page value'),
|
557
|
+
detail: I18n.translate('jsonapi-resources.exceptions.invalid_page_value.detail',
|
558
|
+
default: "#{value} is not a valid value for #{page} page parameter.",
|
559
|
+
value: value, page: page))]
|
560
|
+
end
|
561
|
+
end
|
562
|
+
end
|
563
|
+
end
|