jsonapi-resources 0.4.4 → 0.5.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 +4 -4
- data/.travis.yml +1 -0
- data/README.md +73 -39
- data/lib/jsonapi-resources.rb +2 -1
- data/lib/jsonapi/acts_as_resource_controller.rb +5 -5
- data/lib/jsonapi/configuration.rb +13 -1
- data/lib/jsonapi/error.rb +2 -2
- data/lib/jsonapi/exceptions.rb +32 -20
- data/lib/jsonapi/link_builder.rb +141 -0
- data/lib/jsonapi/operation.rb +34 -34
- data/lib/jsonapi/operation_result.rb +3 -3
- data/lib/jsonapi/operations_processor.rb +7 -7
- data/lib/jsonapi/{association.rb → relationship.rb} +12 -4
- data/lib/jsonapi/request.rb +85 -85
- data/lib/jsonapi/resource.rb +153 -121
- data/lib/jsonapi/resource_serializer.rb +89 -92
- data/lib/jsonapi/resources/version.rb +1 -1
- data/lib/jsonapi/response_document.rb +1 -1
- data/lib/jsonapi/routing_ext.rb +42 -42
- data/test/controllers/controller_test.rb +90 -100
- data/test/fixtures/active_record.rb +38 -5
- data/test/fixtures/author_details.yml +9 -0
- data/test/fixtures/vehicles.yml +10 -2
- data/test/integration/requests/request_test.rb +17 -17
- data/test/integration/routes/routes_test.rb +20 -20
- data/test/test_helper.rb +18 -1
- data/test/unit/jsonapi_request/jsonapi_request_test.rb +1 -1
- data/test/unit/operation/operations_processor_test.rb +21 -21
- data/test/unit/resource/resource_test.rb +13 -13
- data/test/unit/serializer/link_builder_test.rb +183 -0
- data/test/unit/serializer/polymorphic_serializer_test.rb +73 -74
- data/test/unit/serializer/serializer_test.rb +342 -91
- metadata +8 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f3abcdf22a7970e7b4e51d624771006f875e857f
|
4
|
+
data.tar.gz: 26703852c97b53b7a044f545a16256024d67522a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fa580d57a12f10e6bd3732ab0b4c6b3818b8daa81ce995110f810d05e71ef16ed4f56b934ccd518c731aca4d617621070fa61e86363acd7fdd72167ffd58fa8e
|
7
|
+
data.tar.gz: 96acb9c3f10654468c1639cd867e0658dc575318b3a452e463955ead6a64f885dbd5482a3b8a4dd803ae76b684560d839c67f507bd925b465f8f90811a43da41
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# JSONAPI::Resources [](http://travis-ci.org/cerebris/jsonapi-resources)
|
1
|
+
# JSONAPI::Resources [](http://travis-ci.org/cerebris/jsonapi-resources) [](https://codeclimate.com/github/cerebris/jsonapi-resources)
|
2
2
|
|
3
3
|
`JSONAPI::Resources`, or "JR", provides a framework for developing a server that complies with the
|
4
4
|
[JSON API](http://jsonapi.org/) specification.
|
@@ -178,10 +178,10 @@ updating the attribute. See the [Value Formatters](#value-formatters) section fo
|
|
178
178
|
|
179
179
|
#### Primary Key
|
180
180
|
|
181
|
-
Resources are always represented using a key of `id`.
|
182
|
-
|
183
|
-
|
184
|
-
|
181
|
+
Resources are always represented using a key of `id`. The resource will interrogate the model to find the primary key.
|
182
|
+
If the underlying model does not use `id` as the primary key _and_ does not support the `primary_key` method you
|
183
|
+
must use the `primary_key` method to tell the resource which field on the model to use as the primary key. **Note:**
|
184
|
+
this _must_ be the actual primary key of the model.
|
185
185
|
|
186
186
|
By default only integer values are allowed for primary key. To change this behavior you can override
|
187
187
|
`verify_key` class method:
|
@@ -212,11 +212,33 @@ class AuthorResource < JSONAPI::Resource
|
|
212
212
|
end
|
213
213
|
```
|
214
214
|
|
215
|
-
####
|
215
|
+
#### Relationships
|
216
216
|
|
217
|
-
Related resources need to be specified in the resource. These
|
217
|
+
Related resources need to be specified in the resource. These may be declared with the `relationship` or the `has_one`
|
218
|
+
and the `has_many` methods.
|
218
219
|
|
219
|
-
Here's a simple example where a post has a single author and an author can have many
|
220
|
+
Here's a simple example using the `relationship` method where a post has a single author and an author can have many
|
221
|
+
posts:
|
222
|
+
|
223
|
+
```ruby
|
224
|
+
class PostResource < JSONAPI::Resource
|
225
|
+
attribute :title, :body
|
226
|
+
|
227
|
+
relationship :author, to: :one
|
228
|
+
end
|
229
|
+
```
|
230
|
+
|
231
|
+
And the corresponding author:
|
232
|
+
|
233
|
+
```ruby
|
234
|
+
class AuthorResource < JSONAPI::Resource
|
235
|
+
attribute :name
|
236
|
+
|
237
|
+
relationship :posts, to: :many
|
238
|
+
end
|
239
|
+
```
|
240
|
+
|
241
|
+
And here's the equivalent resources using the `has_one` and `has_many` methods:
|
220
242
|
|
221
243
|
```ruby
|
222
244
|
class PostResource < JSONAPI::Resource
|
@@ -238,14 +260,17 @@ end
|
|
238
260
|
|
239
261
|
##### Options
|
240
262
|
|
241
|
-
The
|
263
|
+
The relationship methods (`relationship`, `has_one`, and `has_many`) support the following options:
|
242
264
|
|
243
265
|
* `class_name` - a string specifying the underlying class for the related resource
|
244
266
|
* `foreign_key` - the method on the resource used to fetch the related resource. Defaults to `<resource_name>_id` for has_one and `<resource_name>_ids` for has_many relationships.
|
245
267
|
* `acts_as_set` - allows the entire set of related records to be replaced in one operation. Defaults to false if not set.
|
246
|
-
* `polymorphic` - set to true to identify
|
268
|
+
* `polymorphic` - set to true to identify relationships that are polymorphic.
|
247
269
|
* `relation_name` - the name of the relation to use on the model. A lambda may be provided which allows conditional selection of the relation based on the context.
|
248
270
|
|
271
|
+
`to_one` relationships support the additional option:
|
272
|
+
* `foreign_key_on` - defaults to `:self`. To indicate that the foreign key is on the related resource specify `:related`.
|
273
|
+
|
249
274
|
Examples:
|
250
275
|
|
251
276
|
```ruby
|
@@ -286,8 +311,10 @@ class BookResource < JSONAPI::Resource
|
|
286
311
|
}
|
287
312
|
...
|
288
313
|
end
|
314
|
+
```
|
289
315
|
|
290
|
-
The polymorphic
|
316
|
+
The polymorphic relationship will require the resource and controller to exist, although routing to them will cause an
|
317
|
+
error.
|
291
318
|
|
292
319
|
```ruby
|
293
320
|
class TaggableResource < JSONAPI::Resource; end
|
@@ -297,7 +324,8 @@ class TaggablesController < JSONAPI::ResourceController; end
|
|
297
324
|
#### Filters
|
298
325
|
|
299
326
|
Filters for locating objects of the resource type are specified in the resource definition. Single filters can be
|
300
|
-
declared using the `filter` method, and multiple filters can be declared with the `filters` method on the resource
|
327
|
+
declared using the `filter` method, and multiple filters can be declared with the `filters` method on the resource
|
328
|
+
class.
|
301
329
|
|
302
330
|
For example:
|
303
331
|
|
@@ -310,7 +338,8 @@ class ContactResource < JSONAPI::Resource
|
|
310
338
|
end
|
311
339
|
```
|
312
340
|
|
313
|
-
Then a request could pass in a filter for example `http://example.com/contacts?filter[name_last]=Smith` and the system
|
341
|
+
Then a request could pass in a filter for example `http://example.com/contacts?filter[name_last]=Smith` and the system
|
342
|
+
will find all people where the last name exactly matches Smith.
|
314
343
|
|
315
344
|
##### Default Filters
|
316
345
|
|
@@ -356,7 +385,7 @@ end
|
|
356
385
|
```
|
357
386
|
|
358
387
|
When you create a relationship, a method is created to fetch record(s) for that relationship. This method calls
|
359
|
-
`records_for(
|
388
|
+
`records_for(relationship_name)` by default.
|
360
389
|
|
361
390
|
```ruby
|
362
391
|
class PostResource < JSONAPI::Resource
|
@@ -374,13 +403,13 @@ end
|
|
374
403
|
|
375
404
|
```
|
376
405
|
|
377
|
-
For example, you may want raise an error if the user is not authorized to view the
|
406
|
+
For example, you may want raise an error if the user is not authorized to view the related records.
|
378
407
|
|
379
408
|
```ruby
|
380
409
|
class BaseResource < JSONAPI::Resource
|
381
|
-
def records_for(
|
410
|
+
def records_for(relationship_name, options={})
|
382
411
|
context = options[:context]
|
383
|
-
records = model.public_send(
|
412
|
+
records = model.public_send(relationship_name)
|
384
413
|
|
385
414
|
unless context.current_user.can_view?(records)
|
386
415
|
raise NotAuthorizedError
|
@@ -563,17 +592,17 @@ Callbacks can also be defined for `JSONAPI::OperationsProcessor` events:
|
|
563
592
|
- `:operation`: Any individual operation.
|
564
593
|
- `:find_operation`: A `find_operation`.
|
565
594
|
- `:show_operation`: A `show_operation`.
|
566
|
-
- `:
|
595
|
+
- `:show_relationship_operation`: A `show_relationship_operation`.
|
567
596
|
- `:show_related_resource_operation`: A `show_related_resource_operation`.
|
568
597
|
- `:show_related_resources_operation`: A `show_related_resources_operation`.
|
569
598
|
- `:create_resource_operation`: A `create_resource_operation`.
|
570
599
|
- `:remove_resource_operation`: A `remove_resource_operation`.
|
571
600
|
- `:replace_fields_operation`: A `replace_fields_operation`.
|
572
|
-
- `:
|
573
|
-
- `:
|
574
|
-
- `:
|
575
|
-
- `:
|
576
|
-
- `:
|
601
|
+
- `:replace_has_one_relationship_operation`: A `replace_has_one_relationship_operation`.
|
602
|
+
- `:create_has_many_relationship_operation`: A `create_has_many_relationship_operation`.
|
603
|
+
- `:replace_has_many_relationship_operation`: A `replace_has_many_relationship_operation`.
|
604
|
+
- `:remove_has_many_relationship_operation`: A `remove_has_many_relationship_operation`.
|
605
|
+
- `:remove_has_one_relationship_operation`: A `remove_has_one_relationship_operation`.
|
577
606
|
|
578
607
|
The operation callbacks have access to two meta data hashes, `@operations_meta` and `@operation_meta`, two links hashes,
|
579
608
|
`@operations_links` and `@operation_links`, the full list of `@operations`, each individual `@operation` and the
|
@@ -874,7 +903,7 @@ An array of resources. Nested resources can be specified with dot notation.
|
|
874
903
|
A hash of resource types and arrays of fields for each resource type.
|
875
904
|
|
876
905
|
*Purpose*: determines which fields are serialized for a resource type. This encompasses both attributes and
|
877
|
-
|
906
|
+
relationship ids in the links section for a resource. Fields are global for a resource type.
|
878
907
|
|
879
908
|
*Example*: ```fields: { people: [:email, :comments], posts: [:title, :author], comments: [:body, :post]}```
|
880
909
|
|
@@ -903,7 +932,7 @@ JR has a couple of helper methods available to assist you with setting up routes
|
|
903
932
|
##### `jsonapi_resources`
|
904
933
|
|
905
934
|
Like `resources` in `ActionDispatch`, `jsonapi_resources` provides resourceful routes mapping between HTTP verbs and URLs
|
906
|
-
and controller actions. This will also setup mappings for relationship URLs for a resource's
|
935
|
+
and controller actions. This will also setup mappings for relationship URLs for a resource's relationships. For example:
|
907
936
|
|
908
937
|
```ruby
|
909
938
|
Rails.application.routes.draw do
|
@@ -916,20 +945,20 @@ gives the following routes
|
|
916
945
|
|
917
946
|
```
|
918
947
|
Prefix Verb URI Pattern Controller#Action
|
919
|
-
|
920
|
-
POST /contacts/:contact_id/
|
921
|
-
DELETE /contacts/:contact_id/
|
922
|
-
contact_phone_numbers GET /contacts/:contact_id/phone-numbers(.:format) phone_numbers#get_related_resources {:
|
948
|
+
contact_relationships_phone_numbers GET /contacts/:contact_id/relationships/phone-numbers(.:format) contacts#show_relationship {:relationship=>"phone_numbers"}
|
949
|
+
POST /contacts/:contact_id/relationships/phone-numbers(.:format) contacts#create_relationship {:relationship=>"phone_numbers"}
|
950
|
+
DELETE /contacts/:contact_id/relationships/phone-numbers/:keys(.:format) contacts#destroy_relationship {:relationship=>"phone_numbers"}
|
951
|
+
contact_phone_numbers GET /contacts/:contact_id/phone-numbers(.:format) phone_numbers#get_related_resources {:relationship=>"phone_numbers", :source=>"contacts"}
|
923
952
|
contacts GET /contacts(.:format) contacts#index
|
924
953
|
POST /contacts(.:format) contacts#create
|
925
954
|
contact GET /contacts/:id(.:format) contacts#show
|
926
955
|
PATCH /contacts/:id(.:format) contacts#update
|
927
956
|
PUT /contacts/:id(.:format) contacts#update
|
928
957
|
DELETE /contacts/:id(.:format) contacts#destroy
|
929
|
-
|
930
|
-
PUT|PATCH /phone-numbers/:phone_number_id/
|
931
|
-
DELETE /phone-numbers/:phone_number_id/
|
932
|
-
phone_number_contact GET /phone-numbers/:phone_number_id/contact(.:format) contacts#get_related_resource {:
|
958
|
+
phone_number_relationships_contact GET /phone-numbers/:phone_number_id/relationships/contact(.:format) phone_numbers#show_relationship {:relationship=>"contact"}
|
959
|
+
PUT|PATCH /phone-numbers/:phone_number_id/relationships/contact(.:format) phone_numbers#update_relationship {:relationship=>"contact"}
|
960
|
+
DELETE /phone-numbers/:phone_number_id/relationships/contact(.:format) phone_numbers#destroy_relationship {:relationship=>"contact"}
|
961
|
+
phone_number_contact GET /phone-numbers/:phone_number_id/contact(.:format) contacts#get_related_resource {:relationship=>"contact", :source=>"phone_numbers"}
|
933
962
|
phone_numbers GET /phone-numbers(.:format) phone_numbers#index
|
934
963
|
POST /phone-numbers(.:format) phone_numbers#create
|
935
964
|
phone_number GET /phone-numbers/:id(.:format) phone_numbers#show
|
@@ -994,9 +1023,9 @@ end
|
|
994
1023
|
Gives the following routes:
|
995
1024
|
|
996
1025
|
```
|
997
|
-
|
998
|
-
POST /contacts/:contact_id/
|
999
|
-
DELETE /contacts/:contact_id/
|
1026
|
+
contact_relationships_phone_numbers GET /contacts/:contact_id/relationships/phone-numbers(.:format) contacts#show_relationship {:relationship=>"phone_numbers"}
|
1027
|
+
POST /contacts/:contact_id/relationships/phone-numbers(.:format) contacts#create_relationship {:relationship=>"phone_numbers"}
|
1028
|
+
DELETE /contacts/:contact_id/relationships/phone-numbers/:keys(.:format) contacts#destroy_relationship {:relationship=>"phone_numbers"}
|
1000
1029
|
contacts GET /contacts(.:format) contacts#index
|
1001
1030
|
POST /contacts(.:format) contacts#create
|
1002
1031
|
contact GET /contacts/:id(.:format) contacts#show
|
@@ -1006,7 +1035,7 @@ contact_links_phone_numbers GET /contacts/:contact_id/links/phone-numbers(.:f
|
|
1006
1035
|
|
1007
1036
|
```
|
1008
1037
|
|
1009
|
-
The new routes allow you to show, create and destroy the
|
1038
|
+
The new routes allow you to show, create and destroy the relationships between resources.
|
1010
1039
|
|
1011
1040
|
###### `jsonapi_related_resources`
|
1012
1041
|
|
@@ -1025,7 +1054,7 @@ gives the following routes:
|
|
1025
1054
|
|
1026
1055
|
```
|
1027
1056
|
Prefix Verb URI Pattern Controller#Action
|
1028
|
-
contact_phone_numbers GET /contacts/:contact_id/phone-numbers(.:format) phone_numbers#get_related_resources {:
|
1057
|
+
contact_phone_numbers GET /contacts/:contact_id/phone-numbers(.:format) phone_numbers#get_related_resources {:relationship=>"phone_numbers", :source=>"contacts"}
|
1029
1058
|
contacts GET /contacts(.:format) contacts#index
|
1030
1059
|
POST /contacts(.:format) contacts#create
|
1031
1060
|
contact GET /contacts/:id(.:format) contacts#show
|
@@ -1053,7 +1082,7 @@ gives the following routes:
|
|
1053
1082
|
|
1054
1083
|
```
|
1055
1084
|
Prefix Verb URI Pattern Controller#Action
|
1056
|
-
phone_number_contact GET /phone-numbers/:phone_number_id/contact(.:format) contacts#get_related_resource {:
|
1085
|
+
phone_number_contact GET /phone-numbers/:phone_number_id/contact(.:format) contacts#get_related_resource {:relationship=>"contact", :source=>"phone_numbers"}
|
1057
1086
|
phone_numbers GET /phone-numbers(.:format) phone_numbers#index
|
1058
1087
|
POST /phone-numbers(.:format) phone_numbers#create
|
1059
1088
|
phone_number GET /phone-numbers/:id(.:format) phone_numbers#show
|
@@ -1248,6 +1277,11 @@ JSONAPI.configure do |config|
|
|
1248
1277
|
# catch this error and render a 403 status code, you should add
|
1249
1278
|
# the `Pundit::NotAuthorizedError` to the `exception_class_whitelist`.
|
1250
1279
|
config.exception_class_whitelist = []
|
1280
|
+
|
1281
|
+
# Resource Linkage
|
1282
|
+
# Controls the serialization of resource linkage for non compound documents
|
1283
|
+
# NOTE: always_include_has_many_linkage_data is not currently implemented
|
1284
|
+
config.always_include_has_one_linkage_data = false
|
1251
1285
|
end
|
1252
1286
|
```
|
1253
1287
|
|
data/lib/jsonapi-resources.rb
CHANGED
@@ -15,8 +15,9 @@ require 'jsonapi/error_codes'
|
|
15
15
|
require 'jsonapi/request'
|
16
16
|
require 'jsonapi/operations_processor'
|
17
17
|
require 'jsonapi/active_record_operations_processor'
|
18
|
-
require 'jsonapi/
|
18
|
+
require 'jsonapi/relationship'
|
19
19
|
require 'jsonapi/include_directives'
|
20
20
|
require 'jsonapi/operation_result'
|
21
21
|
require 'jsonapi/operation_results'
|
22
22
|
require 'jsonapi/callbacks'
|
23
|
+
require 'jsonapi/link_builder'
|
@@ -5,7 +5,7 @@ module JSONAPI
|
|
5
5
|
extend ActiveSupport::Concern
|
6
6
|
|
7
7
|
included do
|
8
|
-
before_filter :ensure_correct_media_type, only: [:create, :update, :
|
8
|
+
before_filter :ensure_correct_media_type, only: [:create, :update, :create_relationship, :update_relationship]
|
9
9
|
append_before_filter :setup_request
|
10
10
|
after_filter :setup_response
|
11
11
|
end
|
@@ -18,7 +18,7 @@ module JSONAPI
|
|
18
18
|
process_request_operations
|
19
19
|
end
|
20
20
|
|
21
|
-
def
|
21
|
+
def show_relationship
|
22
22
|
process_request_operations
|
23
23
|
end
|
24
24
|
|
@@ -26,11 +26,11 @@ module JSONAPI
|
|
26
26
|
process_request_operations
|
27
27
|
end
|
28
28
|
|
29
|
-
def
|
29
|
+
def create_relationship
|
30
30
|
process_request_operations
|
31
31
|
end
|
32
32
|
|
33
|
-
def
|
33
|
+
def update_relationship
|
34
34
|
process_request_operations
|
35
35
|
end
|
36
36
|
|
@@ -42,7 +42,7 @@ module JSONAPI
|
|
42
42
|
process_request_operations
|
43
43
|
end
|
44
44
|
|
45
|
-
def
|
45
|
+
def destroy_relationship
|
46
46
|
process_request_operations
|
47
47
|
end
|
48
48
|
|
@@ -17,7 +17,9 @@ module JSONAPI
|
|
17
17
|
:top_level_links_include_pagination,
|
18
18
|
:top_level_meta_include_record_count,
|
19
19
|
:top_level_meta_record_count_key,
|
20
|
-
:exception_class_whitelist
|
20
|
+
:exception_class_whitelist,
|
21
|
+
:always_include_to_one_linkage_data,
|
22
|
+
:always_include_to_many_linkage_data
|
21
23
|
|
22
24
|
def initialize
|
23
25
|
#:underscored_key, :camelized_key, :dasherized_key, or custom
|
@@ -54,6 +56,12 @@ module JSONAPI
|
|
54
56
|
# catch this error and render a 403 status code, you should add
|
55
57
|
# the `Pundit::NotAuthorizedError` to the `exception_class_whitelist`.
|
56
58
|
self.exception_class_whitelist = []
|
59
|
+
|
60
|
+
# Resource Linkage
|
61
|
+
# Controls the serialization of resource linkage for non compound documents
|
62
|
+
# NOTE: always_include_to_many_linkage_data is not currently implemented
|
63
|
+
self.always_include_to_one_linkage_data = false
|
64
|
+
self.always_include_to_many_linkage_data = false
|
57
65
|
end
|
58
66
|
|
59
67
|
def json_key_format=(format)
|
@@ -88,6 +96,10 @@ module JSONAPI
|
|
88
96
|
attr_writer :top_level_meta_record_count_key
|
89
97
|
|
90
98
|
attr_writer :exception_class_whitelist
|
99
|
+
|
100
|
+
attr_writer :always_include_to_one_linkage_data
|
101
|
+
|
102
|
+
attr_writer :always_include_to_many_linkage_data
|
91
103
|
end
|
92
104
|
|
93
105
|
class << self
|
data/lib/jsonapi/error.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module JSONAPI
|
2
2
|
class Error
|
3
|
-
attr_accessor :title, :detail, :id, :href, :code, :
|
3
|
+
attr_accessor :title, :detail, :id, :href, :code, :source, :links, :status
|
4
4
|
|
5
5
|
def initialize(options = {})
|
6
6
|
@title = options[:title]
|
@@ -12,7 +12,7 @@ module JSONAPI
|
|
12
12
|
else
|
13
13
|
options[:code]
|
14
14
|
end
|
15
|
-
@
|
15
|
+
@source = options[:source]
|
16
16
|
@links = options[:links]
|
17
17
|
@status = options[:status]
|
18
18
|
end
|
data/lib/jsonapi/exceptions.rb
CHANGED
@@ -73,12 +73,12 @@ module JSONAPI
|
|
73
73
|
end
|
74
74
|
end
|
75
75
|
|
76
|
-
class
|
76
|
+
class ToManySetReplacementForbidden < Error
|
77
77
|
def errors
|
78
78
|
[JSONAPI::Error.new(code: JSONAPI::FORBIDDEN,
|
79
79
|
status: :forbidden,
|
80
80
|
title: 'Complete replacement forbidden',
|
81
|
-
detail: 'Complete replacement forbidden for this
|
81
|
+
detail: 'Complete replacement forbidden for this relationship')]
|
82
82
|
end
|
83
83
|
end
|
84
84
|
|
@@ -188,17 +188,17 @@ module JSONAPI
|
|
188
188
|
end
|
189
189
|
|
190
190
|
class InvalidInclude < Error
|
191
|
-
attr_accessor :
|
192
|
-
def initialize(resource,
|
191
|
+
attr_accessor :relationship, :resource
|
192
|
+
def initialize(resource, relationship)
|
193
193
|
@resource = resource
|
194
|
-
@
|
194
|
+
@relationship = relationship
|
195
195
|
end
|
196
196
|
|
197
197
|
def errors
|
198
198
|
[JSONAPI::Error.new(code: JSONAPI::INVALID_INCLUDE,
|
199
199
|
status: :bad_request,
|
200
200
|
title: 'Invalid field',
|
201
|
-
detail: "#{
|
201
|
+
detail: "#{relationship} is not a valid relationship of #{resource}")]
|
202
202
|
end
|
203
203
|
end
|
204
204
|
|
@@ -294,9 +294,11 @@ module JSONAPI
|
|
294
294
|
end
|
295
295
|
|
296
296
|
class ValidationErrors < Error
|
297
|
-
|
298
|
-
|
299
|
-
|
297
|
+
attr_reader :error_messages, :resource_relationships
|
298
|
+
|
299
|
+
def initialize(resource)
|
300
|
+
@error_messages = resource.model.errors.messages
|
301
|
+
@resource_relationships = resource.class._relationships.keys
|
300
302
|
@key_formatter = JSONAPI.configuration.key_formatter
|
301
303
|
end
|
302
304
|
|
@@ -305,16 +307,26 @@ module JSONAPI
|
|
305
307
|
end
|
306
308
|
|
307
309
|
def errors
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
310
|
+
error_messages.flat_map do |attr_key, messages|
|
311
|
+
messages.map { |message| json_api_error(attr_key, message) }
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
private
|
316
|
+
|
317
|
+
def json_api_error(attr_key, message)
|
318
|
+
JSONAPI::Error.new(code: JSONAPI::VALIDATION_ERROR,
|
319
|
+
status: :unprocessable_entity,
|
320
|
+
title: "#{format_key(attr_key)} - #{message}",
|
321
|
+
detail: message,
|
322
|
+
source: { pointer: pointer(attr_key) })
|
323
|
+
end
|
324
|
+
|
325
|
+
def pointer(attr_or_relationship_name)
|
326
|
+
if resource_relationships.include?(attr_or_relationship_name)
|
327
|
+
"/data/relationships/#{attr_or_relationship_name}"
|
328
|
+
else
|
329
|
+
"/data/attributes/#{attr_or_relationship_name}"
|
318
330
|
end
|
319
331
|
end
|
320
332
|
end
|
@@ -358,7 +370,7 @@ module JSONAPI
|
|
358
370
|
def initialize(page, value, msg = nil)
|
359
371
|
@page = page
|
360
372
|
@value = value
|
361
|
-
@msg = msg
|
373
|
+
@msg = msg || "#{value} is not a valid value for #{page} page parameter."
|
362
374
|
end
|
363
375
|
|
364
376
|
def errors
|