fun_with_json_api 0.0.2 → 0.0.3
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/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
@@ -0,0 +1,112 @@
|
|
1
|
+
module FunWithJsonApi
|
2
|
+
class FindResourceFromDocument
|
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
|
+
|
12
|
+
def initialize(api_document, deserializer)
|
13
|
+
@api_document = api_document.deep_stringify_keys
|
14
|
+
@deserializer = deserializer
|
15
|
+
end
|
16
|
+
|
17
|
+
def find
|
18
|
+
raise build_invalid_document_error unless document_is_valid?
|
19
|
+
|
20
|
+
# Resource is being set to nil/null
|
21
|
+
return nil if document_is_null_resource?
|
22
|
+
|
23
|
+
# Ensure the document matches the expected resource
|
24
|
+
raise build_invalid_document_type_error unless document_matches_resource_type?
|
25
|
+
|
26
|
+
# Load resource from id value
|
27
|
+
deserializer.load_resource_from_id_value(document_id).tap do |resource|
|
28
|
+
raise build_missing_resource_error if resource.nil?
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def document_id
|
33
|
+
@document_id ||= api_document['data']['id']
|
34
|
+
end
|
35
|
+
|
36
|
+
def document_type
|
37
|
+
@document_type ||= api_document['data']['type']
|
38
|
+
end
|
39
|
+
|
40
|
+
def resource_type
|
41
|
+
@resource_type ||= deserializer.type
|
42
|
+
end
|
43
|
+
|
44
|
+
def document_is_valid?
|
45
|
+
api_document.key?('data') && (
|
46
|
+
api_document['data'].is_a?(Hash) || document_is_null_resource?
|
47
|
+
)
|
48
|
+
end
|
49
|
+
|
50
|
+
def document_is_null_resource?
|
51
|
+
api_document['data'].nil?
|
52
|
+
end
|
53
|
+
|
54
|
+
def document_matches_resource_type?
|
55
|
+
resource_type == document_type
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def build_invalid_document_error
|
61
|
+
payload = ExceptionPayload.new
|
62
|
+
payload.pointer = '/data'
|
63
|
+
payload.detail = document_is_invalid_message
|
64
|
+
Exceptions::InvalidDocument.new(
|
65
|
+
"Expected root data element with hash or null: #{api_document.inspect}",
|
66
|
+
payload
|
67
|
+
)
|
68
|
+
end
|
69
|
+
|
70
|
+
def build_invalid_document_type_error
|
71
|
+
message = "'#{document_type}' did not match expected resource type: '#{resource_type}'"
|
72
|
+
payload = ExceptionPayload.new(
|
73
|
+
detail: document_type_does_not_match_endpoint_message
|
74
|
+
)
|
75
|
+
Exceptions::InvalidDocumentType.new(message, payload)
|
76
|
+
end
|
77
|
+
|
78
|
+
def build_missing_resource_error
|
79
|
+
deserializer_name = deserializer.class.name || 'Deserializer'
|
80
|
+
message = "#{deserializer_name} was unable to find resource by '#{deserializer.id_param}'"\
|
81
|
+
": '#{document_id}'"
|
82
|
+
payload = ExceptionPayload.new
|
83
|
+
payload.pointer = '/data/id'
|
84
|
+
payload.detail = missing_resource_message
|
85
|
+
Exceptions::MissingResource.new(message, payload)
|
86
|
+
end
|
87
|
+
|
88
|
+
def document_is_invalid_message
|
89
|
+
I18n.t(
|
90
|
+
:invalid_document,
|
91
|
+
scope: 'fun_with_json_api.find_resource_from_document'
|
92
|
+
)
|
93
|
+
end
|
94
|
+
|
95
|
+
def document_type_does_not_match_endpoint_message
|
96
|
+
I18n.t(
|
97
|
+
:invalid_document_type,
|
98
|
+
resource: resource_type,
|
99
|
+
scope: 'fun_with_json_api.find_resource_from_document'
|
100
|
+
)
|
101
|
+
end
|
102
|
+
|
103
|
+
def missing_resource_message
|
104
|
+
I18n.t(
|
105
|
+
:missing_resource,
|
106
|
+
resource: resource_type,
|
107
|
+
resource_id: document_id,
|
108
|
+
scope: 'fun_with_json_api.find_resource_from_document'
|
109
|
+
)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -1,9 +1,38 @@
|
|
1
1
|
require 'fun_with_json_api/controller_methods'
|
2
|
+
require 'fun_with_json_api/action_controller_extensions/serialization'
|
3
|
+
|
4
|
+
Mime::Type.register FunWithJsonApi::MEDIA_TYPE, :json_api
|
2
5
|
|
3
6
|
module FunWithJsonApi
|
4
7
|
# Mountable engine for fun with json_api
|
5
8
|
class Railtie < Rails::Railtie
|
6
|
-
initializer
|
9
|
+
initializer :register_json_api_mime_type do
|
10
|
+
parsers =
|
11
|
+
if Rails::VERSION::MAJOR >= 5
|
12
|
+
ActionDispatch::Http::Parameters
|
13
|
+
else
|
14
|
+
ActionDispatch::ParamsParser
|
15
|
+
end
|
16
|
+
|
17
|
+
parsers::DEFAULT_PARSERS[Mime::Type.lookup(FunWithJsonApi::MEDIA_TYPE)] = lambda do |body|
|
18
|
+
data = JSON.parse(body)
|
19
|
+
data = { _json: data } unless data.is_a?(Hash)
|
20
|
+
data.with_indifferent_access
|
21
|
+
end
|
22
|
+
end
|
23
|
+
initializer :register_json_api_renderer do
|
24
|
+
ActionController::Renderers.add :json_api do |json, options|
|
25
|
+
json = json.to_json(options) unless json.is_a?(String)
|
26
|
+
self.content_type ||= Mime::Type.lookup(FunWithJsonApi::MEDIA_TYPE)
|
27
|
+
json
|
28
|
+
end
|
29
|
+
end
|
30
|
+
initializer :register_json_api_serializers do
|
31
|
+
ActiveSupport.on_load(:action_controller) do
|
32
|
+
include(FunWithJsonApi::ActionControllerExtensions::Serialization)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
initializer :add_json_api_locales do
|
7
36
|
translations = File.expand_path('../../../config/locales/**/*.{rb,yml}', __FILE__)
|
8
37
|
Dir.glob(translations) { |f| config.i18n.load_path << f.to_s }
|
9
38
|
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'fun_with_json_api/exception'
|
2
|
+
|
3
|
+
module FunWithJsonApi
|
4
|
+
class SchemaValidator
|
5
|
+
def self.check(api_document, deserializer, resource)
|
6
|
+
new(api_document, deserializer, resource).check
|
7
|
+
end
|
8
|
+
|
9
|
+
private_class_method :new
|
10
|
+
|
11
|
+
attr_reader :api_document
|
12
|
+
attr_reader :deserializer
|
13
|
+
attr_reader :resource
|
14
|
+
|
15
|
+
def initialize(api_document, deserializer, resource)
|
16
|
+
@api_document = api_document.deep_stringify_keys
|
17
|
+
@deserializer = deserializer
|
18
|
+
@resource = resource
|
19
|
+
end
|
20
|
+
|
21
|
+
def check
|
22
|
+
FunWithJsonApi::SchemaValidators::CheckDocumentTypeMatchesResource.call(self)
|
23
|
+
FunWithJsonApi::SchemaValidators::CheckDocumentIdMatchesResource.call(self)
|
24
|
+
FunWithJsonApi::SchemaValidators::CheckAttributes.call(api_document, deserializer)
|
25
|
+
FunWithJsonApi::SchemaValidators::CheckRelationships.call(api_document, deserializer)
|
26
|
+
end
|
27
|
+
|
28
|
+
def document_id
|
29
|
+
@document_id ||= api_document['data']['id']
|
30
|
+
end
|
31
|
+
|
32
|
+
def document_type
|
33
|
+
@document_type ||= api_document['data']['type']
|
34
|
+
end
|
35
|
+
|
36
|
+
def resource_id
|
37
|
+
@resource_id ||= resource.send(deserializer.id_param).to_s
|
38
|
+
end
|
39
|
+
|
40
|
+
def resource_type
|
41
|
+
@resource_type ||= deserializer.type
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Load known Schema Validators
|
47
|
+
Dir["#{File.dirname(__FILE__)}/schema_validators/**/*.rb"].each { |f| require f }
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module FunWithJsonApi
|
2
|
+
module SchemaValidators
|
3
|
+
class CheckAttributes
|
4
|
+
def self.call(api_document, deserializer)
|
5
|
+
new(api_document, deserializer).call
|
6
|
+
end
|
7
|
+
|
8
|
+
attr_reader :api_document
|
9
|
+
attr_reader :deserializer
|
10
|
+
|
11
|
+
def initialize(api_document, deserializer)
|
12
|
+
@api_document = api_document
|
13
|
+
@deserializer = deserializer
|
14
|
+
end
|
15
|
+
|
16
|
+
def call
|
17
|
+
attributes = api_document['data'].fetch('attributes', {}).keys
|
18
|
+
unknown = attributes.reject { |attribute| resource_attributes.include?(attribute) }
|
19
|
+
|
20
|
+
return true if unknown.empty?
|
21
|
+
|
22
|
+
raise build_unknown_attribute_error(unknown)
|
23
|
+
end
|
24
|
+
|
25
|
+
def resource_attributes
|
26
|
+
@resource_attributes ||= deserializer.attributes.map(&:name).map(&:to_s)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def build_unknown_attribute_error(unknown_attributes)
|
32
|
+
payload = unknown_attributes.map do |attribute|
|
33
|
+
ExceptionPayload.new(
|
34
|
+
detail: unknown_attribute_error(attribute),
|
35
|
+
pointer: "/data/attributes/#{attribute}"
|
36
|
+
)
|
37
|
+
end
|
38
|
+
message = 'Unknown attributes were provided by endpoint'
|
39
|
+
FunWithJsonApi::Exceptions::UnknownAttribute.new(message, payload)
|
40
|
+
end
|
41
|
+
|
42
|
+
def unknown_attribute_error(attribute)
|
43
|
+
I18n.t(
|
44
|
+
:unknown_attribute_for_resource,
|
45
|
+
attribute: attribute,
|
46
|
+
resource: deserializer.type,
|
47
|
+
scope: 'fun_with_json_api.schema_validators'
|
48
|
+
)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module FunWithJsonApi
|
2
|
+
module SchemaValidators
|
3
|
+
class CheckDocumentIdMatchesResource
|
4
|
+
def self.call(schema_validator)
|
5
|
+
new(schema_validator).call
|
6
|
+
end
|
7
|
+
|
8
|
+
attr_reader :schema_validator
|
9
|
+
delegate :resource,
|
10
|
+
:document_id,
|
11
|
+
:resource_id,
|
12
|
+
:resource_type,
|
13
|
+
:deserializer,
|
14
|
+
to: :schema_validator
|
15
|
+
|
16
|
+
def initialize(schema_validator)
|
17
|
+
@schema_validator = schema_validator
|
18
|
+
end
|
19
|
+
|
20
|
+
def call
|
21
|
+
if resource.try(:persisted?)
|
22
|
+
# Ensure correct update document is being sent
|
23
|
+
check_resource_id_matches_document_id
|
24
|
+
elsif document_id
|
25
|
+
# Ensure correct create document is being sent
|
26
|
+
check_resource_id_can_be_client_generated
|
27
|
+
check_resource_id_has_not_already_been_used
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def check_resource_id_matches_document_id
|
32
|
+
if document_id != resource_id
|
33
|
+
message = "resource id '#{resource_id}' does not match the expected id for"\
|
34
|
+
" '#{resource_type}': '#{document_id}'"
|
35
|
+
payload = ExceptionPayload.new(
|
36
|
+
detail: document_id_does_not_match_resource_message
|
37
|
+
)
|
38
|
+
raise Exceptions::InvalidDocumentIdentifier.new(message, payload)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def check_resource_id_can_be_client_generated
|
43
|
+
# Ensure id has been provided as an attribute
|
44
|
+
if deserializer.attributes.none? { |attribute| attribute.name == :id }
|
45
|
+
deserializer_name = deserializer.class.name || 'Deserializer'
|
46
|
+
message = "id parameter for '#{resource_type}' cannot be set"\
|
47
|
+
" as it has not been defined as a #{deserializer_name} attribute"
|
48
|
+
payload = ExceptionPayload.new(
|
49
|
+
detail: resource_id_can_not_be_client_generated_message
|
50
|
+
)
|
51
|
+
raise Exceptions::IllegalClientGeneratedIdentifier.new(message, payload)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def check_resource_id_has_not_already_been_used
|
56
|
+
if (existing = deserializer.load_resource_from_id_value(document_id))
|
57
|
+
deserializer_class = deserializer.class.name || 'Deserializer'
|
58
|
+
message = "#{deserializer_class}#load_resource_from_id_value for '#{resource_type}' has"\
|
59
|
+
' found a existing resource matching document id'\
|
60
|
+
": #{existing.class.name}##{existing.id}"
|
61
|
+
payload = ExceptionPayload.new(
|
62
|
+
detail: resource_id_has_already_been_used_message
|
63
|
+
)
|
64
|
+
raise Exceptions::InvalidClientGeneratedIdentifier.new(message, payload)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def document_id_does_not_match_resource_message
|
71
|
+
I18n.t(
|
72
|
+
:document_id_does_not_match_resource,
|
73
|
+
expected: resource_id,
|
74
|
+
scope: 'fun_with_json_api.schema_validators'
|
75
|
+
)
|
76
|
+
end
|
77
|
+
|
78
|
+
def resource_id_can_not_be_client_generated_message
|
79
|
+
I18n.t(
|
80
|
+
:resource_id_can_not_be_client_generated,
|
81
|
+
resource: resource_type,
|
82
|
+
scope: 'fun_with_json_api.schema_validators'
|
83
|
+
)
|
84
|
+
end
|
85
|
+
|
86
|
+
def resource_id_has_already_been_used_message
|
87
|
+
I18n.t(
|
88
|
+
:resource_id_has_already_been_assigned,
|
89
|
+
id: document_id,
|
90
|
+
resource: resource_type,
|
91
|
+
scope: 'fun_with_json_api.schema_validators'
|
92
|
+
)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module FunWithJsonApi
|
2
|
+
module SchemaValidators
|
3
|
+
class CheckDocumentTypeMatchesResource
|
4
|
+
def self.call(schema_validator)
|
5
|
+
new(schema_validator).call
|
6
|
+
end
|
7
|
+
|
8
|
+
attr_reader :schema_validator
|
9
|
+
delegate :document_type,
|
10
|
+
:resource_type,
|
11
|
+
:deserializer,
|
12
|
+
to: :schema_validator
|
13
|
+
|
14
|
+
def initialize(schema_validator)
|
15
|
+
@schema_validator = schema_validator
|
16
|
+
end
|
17
|
+
|
18
|
+
def call
|
19
|
+
if document_type != resource_type
|
20
|
+
message = "'#{document_type}' does not match the expected resource"\
|
21
|
+
": #{resource_type}"
|
22
|
+
payload = ExceptionPayload.new(
|
23
|
+
detail: document_type_does_not_match_endpoint_message
|
24
|
+
)
|
25
|
+
raise Exceptions::InvalidDocumentType.new(message, payload)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def document_type_does_not_match_endpoint_message
|
32
|
+
I18n.t(
|
33
|
+
:document_type_does_not_match_endpoint,
|
34
|
+
expected: resource_type,
|
35
|
+
scope: 'fun_with_json_api.schema_validators'
|
36
|
+
)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
module FunWithJsonApi
|
2
|
+
module SchemaValidators
|
3
|
+
class CheckRelationships
|
4
|
+
def self.call(api_document, deserializer)
|
5
|
+
new(api_document, deserializer).call
|
6
|
+
end
|
7
|
+
|
8
|
+
attr_reader :api_document
|
9
|
+
attr_reader :deserializer
|
10
|
+
|
11
|
+
def initialize(api_document, deserializer)
|
12
|
+
@api_document = api_document
|
13
|
+
@deserializer = deserializer
|
14
|
+
end
|
15
|
+
|
16
|
+
def call
|
17
|
+
relationships = api_document['data'].fetch('relationships', {})
|
18
|
+
|
19
|
+
check_for_unknown_relationships! relationships.keys
|
20
|
+
check_for_invalid_relationship_type! relationships
|
21
|
+
|
22
|
+
true
|
23
|
+
end
|
24
|
+
|
25
|
+
def check_for_unknown_relationships!(relationship_keys)
|
26
|
+
unknown = relationship_keys.reject { |rel| resource_relationships.include?(rel) }
|
27
|
+
return if unknown.empty?
|
28
|
+
|
29
|
+
raise build_unknown_relationship_error(unknown)
|
30
|
+
end
|
31
|
+
|
32
|
+
def check_for_invalid_relationship_type!(relationships_hash)
|
33
|
+
payload = build_invalid_relationship_type_payload(relationships_hash)
|
34
|
+
return if payload.empty?
|
35
|
+
|
36
|
+
message = 'A relationship received data with an incorrect type'
|
37
|
+
raise FunWithJsonApi::Exceptions::InvalidRelationshipType.new(message, payload)
|
38
|
+
end
|
39
|
+
|
40
|
+
def check_for_invalid_relationship_type_in_collection!(relationship, collection_data)
|
41
|
+
return unless collection_data.is_a?(Array)
|
42
|
+
|
43
|
+
collection_data.each_with_index.map do |item, index|
|
44
|
+
next if item['type'] == relationship.type
|
45
|
+
|
46
|
+
build_invalid_collection_item_payload(relationship, index)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def check_for_invalid_relationship_type_in_relationship!(relationship, relationship_data)
|
51
|
+
return unless relationship_data.is_a?(Hash)
|
52
|
+
return if relationship_data['type'] == relationship.type
|
53
|
+
|
54
|
+
build_invalid_relationship_item_payload(relationship)
|
55
|
+
end
|
56
|
+
|
57
|
+
def resource_relationships
|
58
|
+
@resource_relationships ||= deserializer.relationships.map(&:name).map(&:to_s)
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def invalid_relationship_type_in_array_message(relationship)
|
64
|
+
I18n.t(
|
65
|
+
:invalid_relationship_type_in_array,
|
66
|
+
relationship: relationship.name,
|
67
|
+
relationship_type: relationship.type,
|
68
|
+
scope: 'fun_with_json_api.schema_validators'
|
69
|
+
)
|
70
|
+
end
|
71
|
+
|
72
|
+
def invalid_relationship_type_in_hash_message(relationship)
|
73
|
+
I18n.t(
|
74
|
+
:invalid_relationship_type_in_hash,
|
75
|
+
relationship: relationship.name,
|
76
|
+
relationship_type: relationship.type,
|
77
|
+
scope: 'fun_with_json_api.schema_validators'
|
78
|
+
)
|
79
|
+
end
|
80
|
+
|
81
|
+
def build_invalid_relationship_type_payload(relationships_hash)
|
82
|
+
deserializer.relationships.map do |relationship|
|
83
|
+
data = relationships_hash.fetch(relationship.name.to_s)['data']
|
84
|
+
if relationship.has_many?
|
85
|
+
check_for_invalid_relationship_type_in_collection!(relationship, data)
|
86
|
+
else
|
87
|
+
check_for_invalid_relationship_type_in_relationship!(relationship, data)
|
88
|
+
end
|
89
|
+
end.flatten.compact
|
90
|
+
end
|
91
|
+
|
92
|
+
def build_invalid_collection_item_payload(relationship, index)
|
93
|
+
ExceptionPayload.new(
|
94
|
+
detail: invalid_relationship_type_in_array_message(relationship),
|
95
|
+
pointer: "/data/relationships/#{relationship.name}/#{index}/type"
|
96
|
+
)
|
97
|
+
end
|
98
|
+
|
99
|
+
def build_invalid_relationship_item_payload(relationship)
|
100
|
+
ExceptionPayload.new(
|
101
|
+
detail: invalid_relationship_type_in_hash_message(relationship),
|
102
|
+
pointer: "/data/relationships/#{relationship.name}/type"
|
103
|
+
)
|
104
|
+
end
|
105
|
+
|
106
|
+
def build_unknown_relationship_error(unknown_relationships)
|
107
|
+
payload = unknown_relationships.map do |relationship|
|
108
|
+
ExceptionPayload.new(
|
109
|
+
detail: unknown_relationship_error(relationship),
|
110
|
+
pointer: "/data/relationships/#{relationship}"
|
111
|
+
)
|
112
|
+
end
|
113
|
+
message = 'Unknown relationships were provided by endpoint'
|
114
|
+
FunWithJsonApi::Exceptions::UnknownRelationship.new(message, payload)
|
115
|
+
end
|
116
|
+
|
117
|
+
def unknown_relationship_error(relationship)
|
118
|
+
I18n.t(
|
119
|
+
:unknown_relationship_for_resource,
|
120
|
+
relationship: relationship,
|
121
|
+
resource: deserializer.type,
|
122
|
+
scope: 'fun_with_json_api.schema_validators'
|
123
|
+
)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|