fun_with_json_api 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Rakefile +4 -1
- data/config/locales/fun_with_json_api.en.yml +29 -2
- data/lib/fun_with_json_api.rb +30 -2
- data/lib/fun_with_json_api/action_controller_extensions/serialization.rb +18 -0
- data/lib/fun_with_json_api/attribute.rb +3 -3
- data/lib/fun_with_json_api/attributes/relationship.rb +37 -23
- data/lib/fun_with_json_api/attributes/relationship_collection.rb +55 -38
- data/lib/fun_with_json_api/attributes/string_attribute.rb +12 -1
- data/lib/fun_with_json_api/attributes/uuid_v4_attribute.rb +27 -0
- data/lib/fun_with_json_api/controller_methods.rb +1 -1
- data/lib/fun_with_json_api/deserializer.rb +61 -8
- data/lib/fun_with_json_api/deserializer_class_methods.rb +37 -7
- data/lib/fun_with_json_api/exceptions/illegal_client_generated_identifier.rb +17 -0
- data/lib/fun_with_json_api/exceptions/invalid_client_generated_identifier.rb +17 -0
- data/lib/fun_with_json_api/exceptions/invalid_document_identifier.rb +17 -0
- data/lib/fun_with_json_api/exceptions/invalid_document_type.rb +20 -0
- data/lib/fun_with_json_api/exceptions/invalid_relationship.rb +5 -3
- data/lib/fun_with_json_api/exceptions/invalid_relationship_type.rb +17 -0
- data/lib/fun_with_json_api/exceptions/missing_resource.rb +15 -0
- data/lib/fun_with_json_api/exceptions/unknown_attribute.rb +15 -0
- data/lib/fun_with_json_api/exceptions/unknown_relationship.rb +15 -0
- data/lib/fun_with_json_api/find_collection_from_document.rb +124 -0
- data/lib/fun_with_json_api/find_resource_from_document.rb +112 -0
- data/lib/fun_with_json_api/pre_deserializer.rb +1 -0
- data/lib/fun_with_json_api/railtie.rb +30 -1
- data/lib/fun_with_json_api/schema_validator.rb +47 -0
- data/lib/fun_with_json_api/schema_validators/check_attributes.rb +52 -0
- data/lib/fun_with_json_api/schema_validators/check_document_id_matches_resource.rb +96 -0
- data/lib/fun_with_json_api/schema_validators/check_document_type_matches_resource.rb +40 -0
- data/lib/fun_with_json_api/schema_validators/check_relationships.rb +127 -0
- data/lib/fun_with_json_api/version.rb +1 -1
- data/spec/dummy/log/test.log +172695 -0
- data/spec/fixtures/active_record.rb +6 -0
- data/spec/fun_with_json_api/controller_methods_spec.rb +8 -3
- data/spec/fun_with_json_api/deserializer_class_methods_spec.rb +14 -6
- data/spec/fun_with_json_api/deserializer_spec.rb +155 -40
- data/spec/fun_with_json_api/exception_spec.rb +9 -9
- data/spec/fun_with_json_api/find_collection_from_document_spec.rb +203 -0
- data/spec/fun_with_json_api/find_resource_from_document_spec.rb +100 -0
- data/spec/fun_with_json_api/pre_deserializer_spec.rb +26 -26
- data/spec/fun_with_json_api/railtie_spec.rb +88 -0
- data/spec/fun_with_json_api/schema_validator_spec.rb +94 -0
- data/spec/fun_with_json_api/schema_validators/check_attributes_spec.rb +52 -0
- data/spec/fun_with_json_api/schema_validators/check_document_id_matches_resource_spec.rb +115 -0
- data/spec/fun_with_json_api/schema_validators/check_document_type_matches_resource_spec.rb +30 -0
- data/spec/fun_with_json_api/schema_validators/check_relationships_spec.rb +150 -0
- data/spec/fun_with_json_api_spec.rb +148 -4
- metadata +49 -4
- data/spec/example_spec.rb +0 -64
@@ -3,7 +3,7 @@ require 'fun_with_json_api/exception_serializer'
|
|
3
3
|
module FunWithJsonApi
|
4
4
|
module ControllerMethods
|
5
5
|
def render_fun_with_json_api_exception(exception)
|
6
|
-
render
|
6
|
+
render json_api: exception,
|
7
7
|
serializer: FunWithJsonApi::ExceptionSerializer,
|
8
8
|
adapter: :json,
|
9
9
|
status: exception.http_status
|
@@ -19,14 +19,28 @@ module FunWithJsonApi
|
|
19
19
|
attr_reader :resource_class
|
20
20
|
|
21
21
|
attr_reader :attributes
|
22
|
-
attr_reader :relationships
|
23
22
|
|
24
23
|
def initialize(options = {})
|
25
24
|
@id_param = options.fetch(:id_param) { self.class.id_param }
|
26
|
-
@type = options
|
25
|
+
@type = options.fetch(:type) { self.class.type }
|
27
26
|
@resource_class = options[:resource_class]
|
28
|
-
@
|
29
|
-
|
27
|
+
@resource_collection = options[:resource_collection] if @type
|
28
|
+
load_attributes_from_options(options)
|
29
|
+
load_relationships_from_options(options)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Loads a collection of of `resource_class` instances with `id_param` matching `id_values`
|
33
|
+
def load_collection_from_id_values(id_values)
|
34
|
+
resource_collection.where(id_param => id_values)
|
35
|
+
end
|
36
|
+
|
37
|
+
def format_collection_ids(collection)
|
38
|
+
collection.map { |resource| resource.public_send(id_param).to_s }
|
39
|
+
end
|
40
|
+
|
41
|
+
# Loads a single instance of `resource_class` with a `id_param` matching `id_value`
|
42
|
+
def load_resource_from_id_value(id_value)
|
43
|
+
resource_collection.find_by(id_param => id_value)
|
30
44
|
end
|
31
45
|
|
32
46
|
# Takes a parsed params hash from ActiveModelSerializers::Deserialization and sanitizes values
|
@@ -37,16 +51,47 @@ module FunWithJsonApi
|
|
37
51
|
]
|
38
52
|
end
|
39
53
|
|
40
|
-
def type
|
41
|
-
@type ||= self.class.type
|
42
|
-
end
|
43
|
-
|
44
54
|
def resource_class
|
45
55
|
@resource_class ||= self.class.resource_class
|
46
56
|
end
|
47
57
|
|
58
|
+
def resource_collection
|
59
|
+
@resource_collection ||= resource_class
|
60
|
+
end
|
61
|
+
|
62
|
+
def relationships
|
63
|
+
relationship_lookup.values
|
64
|
+
end
|
65
|
+
|
66
|
+
def relationship_for(resource_name)
|
67
|
+
relationship_lookup.fetch(resource_name)
|
68
|
+
end
|
69
|
+
|
48
70
|
private
|
49
71
|
|
72
|
+
attr_reader :relationship_lookup
|
73
|
+
|
74
|
+
def load_attributes_from_options(options)
|
75
|
+
@attributes = filter_attributes_by_name(options[:attributes], self.class.attributes)
|
76
|
+
end
|
77
|
+
|
78
|
+
def load_relationships_from_options(options = {})
|
79
|
+
options_config = {}
|
80
|
+
|
81
|
+
# Filter resources and build an options hash for each
|
82
|
+
filter_relationships_by_name(
|
83
|
+
options[:relationships], self.class.relationship_names
|
84
|
+
).each do |relationship|
|
85
|
+
options_config[relationship] = options.fetch(relationship, {})
|
86
|
+
end
|
87
|
+
|
88
|
+
# Build the relationships and store them into a lookup hash
|
89
|
+
@relationship_lookup = {}
|
90
|
+
self.class.build_relationships(options_config).each do |relationship|
|
91
|
+
@relationship_lookup[relationship.name] = relationship
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
50
95
|
def filter_attributes_by_name(attribute_names, attributes)
|
51
96
|
if attribute_names
|
52
97
|
attributes.keep_if { |attribute| attribute_names.include?(attribute.name) }
|
@@ -55,6 +100,14 @@ module FunWithJsonApi
|
|
55
100
|
end
|
56
101
|
end
|
57
102
|
|
103
|
+
def filter_relationships_by_name(relationship_names, relationships)
|
104
|
+
if relationship_names
|
105
|
+
relationships.keep_if { |relationship| relationship_names.include?(relationship) }
|
106
|
+
else
|
107
|
+
relationships
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
58
111
|
# Calls <attribute.as> on the current instance, override the #<as> method to change loading
|
59
112
|
def serialize_attribute_values(attributes, params)
|
60
113
|
attributes.select { |attribute| params.key?(attribute.param_value) }
|
@@ -3,9 +3,13 @@ require 'fun_with_json_api/attribute'
|
|
3
3
|
module FunWithJsonApi
|
4
4
|
# Provides a basic DSL for defining a FunWithJsonApi::Deserializer
|
5
5
|
module DeserializerClassMethods
|
6
|
-
def id_param(id_param = nil)
|
7
|
-
@id_param = id_param if id_param
|
8
|
-
@id_param || :id
|
6
|
+
def id_param(id_param = nil, format: false)
|
7
|
+
@id_param = id_param.to_sym if id_param
|
8
|
+
(@id_param || :id).tap do |param|
|
9
|
+
if format
|
10
|
+
attribute(:id, as: param, format: format) # Create a new id attribute
|
11
|
+
end
|
12
|
+
end
|
9
13
|
end
|
10
14
|
|
11
15
|
def type(type = nil)
|
@@ -39,7 +43,7 @@ module FunWithJsonApi
|
|
39
43
|
deserializer_class_or_callable,
|
40
44
|
options
|
41
45
|
).tap do |relationship|
|
42
|
-
|
46
|
+
add_parse_resource_method(relationship)
|
43
47
|
relationships << relationship
|
44
48
|
end
|
45
49
|
end
|
@@ -52,26 +56,52 @@ module FunWithJsonApi
|
|
52
56
|
deserializer_class_or_callable,
|
53
57
|
options
|
54
58
|
).tap do |relationship|
|
55
|
-
|
59
|
+
add_parse_resource_method(relationship)
|
56
60
|
relationships << relationship
|
57
61
|
end
|
58
62
|
end
|
59
63
|
|
60
64
|
# rubocop:enable Style/PredicateName
|
61
65
|
|
62
|
-
def
|
63
|
-
|
66
|
+
def relationship_names
|
67
|
+
relationships.map(&:name)
|
68
|
+
end
|
69
|
+
|
70
|
+
def build_relationships(options)
|
71
|
+
options.map do |name, relationship_options|
|
72
|
+
relationship = relationships.detect { |rel| rel.name == name }
|
73
|
+
relationship.class.create(
|
74
|
+
relationship.name,
|
75
|
+
relationship.deserializer_class,
|
76
|
+
relationship_options.reverse_merge(relationship.options)
|
77
|
+
)
|
78
|
+
end
|
64
79
|
end
|
65
80
|
|
66
81
|
private
|
67
82
|
|
83
|
+
def relationships
|
84
|
+
@relationships ||= []
|
85
|
+
end
|
86
|
+
|
68
87
|
def add_parse_attribute_method(attribute)
|
69
88
|
define_method(attribute.sanitize_attribute_method) do |param_value|
|
70
89
|
attribute.call(param_value)
|
71
90
|
end
|
72
91
|
end
|
73
92
|
|
93
|
+
def add_parse_resource_method(resource)
|
94
|
+
define_method(resource.sanitize_attribute_method) do |param_value|
|
95
|
+
relationship_for(resource.name).call(param_value)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
74
99
|
def type_from_class_name
|
100
|
+
if name.nil?
|
101
|
+
Rails.logger.warn 'Unable to determine type for anonymous Deserializer'
|
102
|
+
return nil
|
103
|
+
end
|
104
|
+
|
75
105
|
resource_class_name = name.demodulize.sub(/Deserializer/, '').underscore
|
76
106
|
if ActiveModelSerializers.config.jsonapi_resource_type == :singular
|
77
107
|
resource_class_name.singularize
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module FunWithJsonApi
|
2
|
+
module Exceptions
|
3
|
+
# A server MUST return 403 Forbidden in response to an unsupported request to create a resource
|
4
|
+
# with a client-generated ID.
|
5
|
+
class IllegalClientGeneratedIdentifier < FunWithJsonApi::Exception
|
6
|
+
EXCEPTION_CODE = 'illegal_client_generated_identifier'.freeze
|
7
|
+
|
8
|
+
def initialize(message, payload = ExceptionPayload.new)
|
9
|
+
payload.code ||= EXCEPTION_CODE
|
10
|
+
payload.title ||= I18n.t(EXCEPTION_CODE, scope: 'fun_with_json_api.exceptions')
|
11
|
+
payload.status ||= '403'
|
12
|
+
payload.pointer ||= '/data/id'
|
13
|
+
super
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module FunWithJsonApi
|
2
|
+
module Exceptions
|
3
|
+
# A server MUST return 409 Conflict when processing a POST request to create a resource with a
|
4
|
+
# client-generated ID that already exists.
|
5
|
+
class InvalidClientGeneratedIdentifier < FunWithJsonApi::Exception
|
6
|
+
EXCEPTION_CODE = 'invalid_client_generated_identifier'.freeze
|
7
|
+
|
8
|
+
def initialize(message, payload = ExceptionPayload.new)
|
9
|
+
payload.code ||= EXCEPTION_CODE
|
10
|
+
payload.title ||= I18n.t(EXCEPTION_CODE, scope: 'fun_with_json_api.exceptions')
|
11
|
+
payload.status ||= '409'
|
12
|
+
payload.pointer ||= '/data/id'
|
13
|
+
super
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module FunWithJsonApi
|
2
|
+
module Exceptions
|
3
|
+
# A server MUST return 409 Conflict when processing a PATCH request in which the resource
|
4
|
+
# object's type and id do not match the server's endpoint
|
5
|
+
class InvalidDocumentIdentifier < FunWithJsonApi::Exception
|
6
|
+
EXCEPTION_CODE = 'invalid_document_identifier'.freeze
|
7
|
+
|
8
|
+
def initialize(message, payload = ExceptionPayload.new)
|
9
|
+
payload.code ||= EXCEPTION_CODE
|
10
|
+
payload.title ||= I18n.t(EXCEPTION_CODE, scope: 'fun_with_json_api.exceptions')
|
11
|
+
payload.status ||= '409'
|
12
|
+
payload.pointer ||= '/data/id'
|
13
|
+
super
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module FunWithJsonApi
|
2
|
+
module Exceptions
|
3
|
+
# A server MUST return 409 Conflict when processing a POST request in which the resource
|
4
|
+
# object's type is not among the type(s) that constitute the collection represented by the
|
5
|
+
# endpoint.
|
6
|
+
class InvalidDocumentType < FunWithJsonApi::Exception
|
7
|
+
EXCEPTION_CODE = 'invalid_document_type'.freeze
|
8
|
+
|
9
|
+
def initialize(message, payload = ExceptionPayload.new)
|
10
|
+
payload = Array.wrap(payload).each do |invalid|
|
11
|
+
invalid.code ||= EXCEPTION_CODE
|
12
|
+
invalid.title ||= I18n.t(EXCEPTION_CODE, scope: 'fun_with_json_api.exceptions')
|
13
|
+
invalid.status ||= '409'
|
14
|
+
invalid.pointer ||= '/data/type'
|
15
|
+
end
|
16
|
+
super
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -3,9 +3,11 @@ module FunWithJsonApi
|
|
3
3
|
# Indicates a Supplied relationships value is not formatted correctly
|
4
4
|
class InvalidRelationship < FunWithJsonApi::Exception
|
5
5
|
def initialize(message, payload = ExceptionPayload.new)
|
6
|
-
payload.
|
7
|
-
|
8
|
-
|
6
|
+
Array.wrap(payload).each do |invalid|
|
7
|
+
invalid.code ||= 'invalid_relationship'
|
8
|
+
invalid.title ||= I18n.t(:invalid_relationship, scope: 'fun_with_json_api.exceptions')
|
9
|
+
invalid.status ||= '400'
|
10
|
+
end
|
9
11
|
super
|
10
12
|
end
|
11
13
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module FunWithJsonApi
|
2
|
+
module Exceptions
|
3
|
+
# Indicates a supplied relationships type does match expected values
|
4
|
+
class InvalidRelationshipType < FunWithJsonApi::Exception
|
5
|
+
ERROR_CODE = 'invalid_relationship_type'.freeze
|
6
|
+
|
7
|
+
def initialize(message, payload = ExceptionPayload.new)
|
8
|
+
Array.wrap(payload).each do |invalid|
|
9
|
+
invalid.code ||= ERROR_CODE
|
10
|
+
invalid.title ||= I18n.t(ERROR_CODE, scope: 'fun_with_json_api.exceptions')
|
11
|
+
invalid.status ||= '409'
|
12
|
+
end
|
13
|
+
super
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module FunWithJsonApi
|
2
|
+
module Exceptions
|
3
|
+
# Indicates a Resource or Collection item was not able to be found
|
4
|
+
class MissingResource < FunWithJsonApi::Exception
|
5
|
+
def initialize(message, payload = ExceptionPayload.new)
|
6
|
+
payload = Array.wrap(payload).each do |missing|
|
7
|
+
missing.code ||= 'missing_resource'
|
8
|
+
missing.title ||= I18n.t('missing_resource', scope: 'fun_with_json_api.exceptions')
|
9
|
+
missing.status ||= '404'
|
10
|
+
end
|
11
|
+
super
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module FunWithJsonApi
|
2
|
+
module Exceptions
|
3
|
+
# Indicates a supplied attribute value is unknown to the current deserializer
|
4
|
+
class UnknownAttribute < FunWithJsonApi::Exception
|
5
|
+
def initialize(message, payload = ExceptionPayload.new)
|
6
|
+
payload = Array.wrap(payload).each do |unknown|
|
7
|
+
unknown.code ||= 'unknown_attribute'
|
8
|
+
unknown.title ||= I18n.t(:unknown_attribute, scope: 'fun_with_json_api.exceptions')
|
9
|
+
unknown.status ||= '422'
|
10
|
+
end
|
11
|
+
super
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module FunWithJsonApi
|
2
|
+
module Exceptions
|
3
|
+
# Indicates a supplied relationship value is unknown to the current deserializer
|
4
|
+
class UnknownRelationship < FunWithJsonApi::Exception
|
5
|
+
def initialize(message, payload = ExceptionPayload.new)
|
6
|
+
payload = Array.wrap(payload).each do |unknown|
|
7
|
+
unknown.code ||= 'unknown_relationship'
|
8
|
+
unknown.title ||= I18n.t(:unknown_relationship, scope: 'fun_with_json_api.exceptions')
|
9
|
+
unknown.status ||= '422'
|
10
|
+
end
|
11
|
+
super
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
module FunWithJsonApi
|
2
|
+
class FindCollectionFromDocument
|
3
|
+
def self.find(*args)
|
4
|
+
new(*args).find
|
5
|
+
end
|
6
|
+
|
7
|
+
private_class_method :new
|
8
|
+
|
9
|
+
attr_reader :api_document
|
10
|
+
attr_reader :deserializer
|
11
|
+
delegate :id_param, :id_param, :resource_class, to: :deserializer
|
12
|
+
|
13
|
+
def initialize(api_document, deserializer)
|
14
|
+
@api_document = api_document.deep_stringify_keys
|
15
|
+
@deserializer = deserializer
|
16
|
+
end
|
17
|
+
|
18
|
+
def find
|
19
|
+
raise build_invalid_document_error unless document_is_valid_collection?
|
20
|
+
|
21
|
+
# Skip the checks, no point running through them for an empty array
|
22
|
+
return [] if document_ids.empty?
|
23
|
+
|
24
|
+
# Ensure the document matches the expected resource
|
25
|
+
check_document_types_match_deserializer!
|
26
|
+
|
27
|
+
# Load resource from id value
|
28
|
+
deserializer.load_collection_from_id_values(document_ids).tap do |collection|
|
29
|
+
check_collection_contains_all_requested_resources!(collection)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def document_ids
|
34
|
+
@document_id ||= api_document['data'].map { |item| item['id'] }
|
35
|
+
end
|
36
|
+
|
37
|
+
def document_types
|
38
|
+
@document_type ||= api_document['data'].map { |item| item['type'] }.uniq
|
39
|
+
end
|
40
|
+
|
41
|
+
def resource_type
|
42
|
+
@resource_type ||= deserializer.type
|
43
|
+
end
|
44
|
+
|
45
|
+
def document_is_valid_collection?
|
46
|
+
api_document.key?('data') && api_document['data'].is_a?(Array)
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def check_collection_contains_all_requested_resources!(collection)
|
52
|
+
if collection.size != document_ids.size
|
53
|
+
collection_ids = deserializer.format_collection_ids(collection)
|
54
|
+
raise build_missing_resources_error(collection_ids)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def check_document_types_match_deserializer!
|
59
|
+
invalid_document_types = document_types.reject { |type| type == resource_type }
|
60
|
+
raise build_invalid_document_types_error if invalid_document_types.any?
|
61
|
+
end
|
62
|
+
|
63
|
+
def build_invalid_document_error
|
64
|
+
payload = ExceptionPayload.new
|
65
|
+
payload.pointer = '/data'
|
66
|
+
payload.detail = 'Expected data to be an Array of resources'
|
67
|
+
Exceptions::InvalidDocument.new(
|
68
|
+
"Expected root data element with an Array: #{api_document.inspect}",
|
69
|
+
payload
|
70
|
+
)
|
71
|
+
end
|
72
|
+
|
73
|
+
def build_invalid_document_types_error
|
74
|
+
message = 'Expected type for each item to match expected resource type'\
|
75
|
+
": '#{resource_type}'"
|
76
|
+
payload = api_document['data'].each_with_index.map do |data, index|
|
77
|
+
next if data['type'] == resource_type
|
78
|
+
ExceptionPayload.new(
|
79
|
+
pointer: "/data/#{index}/type",
|
80
|
+
detail: document_type_does_not_match_endpoint_message(data['type'])
|
81
|
+
)
|
82
|
+
end.reject(&:nil?)
|
83
|
+
Exceptions::InvalidDocumentType.new(message, payload)
|
84
|
+
end
|
85
|
+
|
86
|
+
def build_missing_resources_error(collection_ids)
|
87
|
+
payload = document_ids.each_with_index.map do |resource_id, index|
|
88
|
+
build_missing_resource_payload(collection_ids, resource_id, index)
|
89
|
+
end.reject(&:nil?)
|
90
|
+
|
91
|
+
missing_values = document_ids.reject { |value| collection_ids.include?(value.to_s) }
|
92
|
+
message = "Couldn't find #{resource_class} items with "\
|
93
|
+
"#{id_param} in #{missing_values.inspect}"
|
94
|
+
Exceptions::MissingResource.new(message, payload)
|
95
|
+
end
|
96
|
+
|
97
|
+
def build_missing_resource_payload(collection_ids, resource_id, index)
|
98
|
+
unless collection_ids.include?(resource_id)
|
99
|
+
ExceptionPayload.new(
|
100
|
+
pointer: "/data/#{index}/id",
|
101
|
+
detail: missing_resource_message(resource_id)
|
102
|
+
)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def document_type_does_not_match_endpoint_message(type)
|
107
|
+
I18n.t(
|
108
|
+
:invalid_document_type,
|
109
|
+
type: type,
|
110
|
+
resource: resource_type,
|
111
|
+
scope: 'fun_with_json_api.find_collection_from_document'
|
112
|
+
)
|
113
|
+
end
|
114
|
+
|
115
|
+
def missing_resource_message(resource_id)
|
116
|
+
I18n.t(
|
117
|
+
:missing_resource,
|
118
|
+
resource: resource_type,
|
119
|
+
resource_id: resource_id,
|
120
|
+
scope: 'fun_with_json_api.find_collection_from_document'
|
121
|
+
)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|