jsonapi-resources 0.4.4 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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 [![Build Status](https://secure.travis-ci.org/cerebris/jsonapi-resources.png?branch=master)](http://travis-ci.org/cerebris/jsonapi-resources)
|
1
|
+
# JSONAPI::Resources [![Build Status](https://secure.travis-ci.org/cerebris/jsonapi-resources.png?branch=master)](http://travis-ci.org/cerebris/jsonapi-resources) [![Code Climate](https://codeclimate.com/github/cerebris/jsonapi-resources/badges/gpa.svg)](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
|