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,88 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe FunWithJsonApi::Railtie do
|
4
|
+
describe 'controller parameters' do
|
5
|
+
context 'with a application/vnd.api+json request content-type', type: :controller do
|
6
|
+
controller do
|
7
|
+
def index
|
8
|
+
# Concatinates /data/id and /data/type from a json_api request
|
9
|
+
render text: "#{params[:data][:id]}:#{params['data']['type']}"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'converts the request body into param values' do
|
14
|
+
json_api_data = { data: { id: '42', type: 'foobar' } }
|
15
|
+
|
16
|
+
get :index,
|
17
|
+
json_api_data.as_json,
|
18
|
+
'Content-Type' => 'application/vnd.api+json'
|
19
|
+
expect(response.body).to eq '42:foobar'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
context 'with an implicit respond_to json_api block', type: :controller do
|
23
|
+
controller do
|
24
|
+
def index
|
25
|
+
respond_to do |format|
|
26
|
+
format.json_api { render text: 'passed' }
|
27
|
+
format.all { render text: 'failed' }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'responds to a json_api format request' do
|
33
|
+
get :index, format: :json_api
|
34
|
+
expect(response.body).to eq 'passed'
|
35
|
+
end
|
36
|
+
it 'responds to a application/vnd.api+json accept header' do
|
37
|
+
request.env['HTTP_ACCEPT'] = 'application/vnd.api+json'
|
38
|
+
get :index
|
39
|
+
expect(response.body).to eq 'passed'
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe 'controller rendering' do
|
45
|
+
context 'with an explicit render json_api call', type: :controller do
|
46
|
+
controller do
|
47
|
+
def index
|
48
|
+
render json_api: { data: { id: '42', type: 'foobar' } }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'renders out the hash as a json_api response' do
|
53
|
+
get :index
|
54
|
+
expect(response.content_type).to eq 'application/vnd.api+json'
|
55
|
+
expect(JSON.parse(response.body)).to eq(
|
56
|
+
'data' => { 'id' => '42', 'type' => 'foobar' }
|
57
|
+
)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
context 'with a resource and a serializer', type: :controller do
|
61
|
+
controller do
|
62
|
+
def index
|
63
|
+
author = ARModels::Author.new(id: 42, name: 'Foo Bar')
|
64
|
+
render json_api: author, serializer: ARModels::AuthorSerializer
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'renders the resource as a json api document' do
|
69
|
+
get :index
|
70
|
+
expect(response.content_type).to eq 'application/vnd.api+json'
|
71
|
+
expect(JSON.parse(response.body)).to eq(
|
72
|
+
'data' => {
|
73
|
+
'id' => '42',
|
74
|
+
'type' => 'person',
|
75
|
+
'attributes' => {
|
76
|
+
'name' => 'Foo Bar'
|
77
|
+
},
|
78
|
+
'relationships' => {
|
79
|
+
'posts' => {
|
80
|
+
'data' => []
|
81
|
+
}
|
82
|
+
}
|
83
|
+
}
|
84
|
+
)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe FunWithJsonApi::SchemaValidator do
|
4
|
+
let(:document) { { data: { id: '42', type: 'examples' } } }
|
5
|
+
let(:deserializer) { instance_double('FunWithJsonApi::Deserializer') }
|
6
|
+
let(:resource) { double('Resource') }
|
7
|
+
subject(:instance) { described_class.send :new, document, deserializer, resource }
|
8
|
+
|
9
|
+
describe '.check' do
|
10
|
+
subject { described_class.check(document, deserializer, resource) }
|
11
|
+
|
12
|
+
it 'calls all schema validator checks with an instance of itself' do
|
13
|
+
[
|
14
|
+
FunWithJsonApi::SchemaValidators::CheckDocumentTypeMatchesResource,
|
15
|
+
FunWithJsonApi::SchemaValidators::CheckDocumentIdMatchesResource
|
16
|
+
].each do |validator_check|
|
17
|
+
expect(validator_check).to receive(:call).with(kind_of(described_class))
|
18
|
+
end
|
19
|
+
|
20
|
+
converted_document = { 'data' => { 'id' => '42', 'type' => 'examples' } }
|
21
|
+
[
|
22
|
+
FunWithJsonApi::SchemaValidators::CheckAttributes,
|
23
|
+
FunWithJsonApi::SchemaValidators::CheckRelationships
|
24
|
+
].each do |property_check|
|
25
|
+
expect(property_check).to receive(:call).with(converted_document, deserializer)
|
26
|
+
end
|
27
|
+
|
28
|
+
subject
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '#document_id' do
|
33
|
+
subject { instance.document_id }
|
34
|
+
|
35
|
+
context 'when the api document has symbolized keys' do
|
36
|
+
context 'when the data attribute has an id value' do
|
37
|
+
let(:document) { { data: { id: '42', type: 'examples' } } }
|
38
|
+
|
39
|
+
it 'returns the /data/id value' do
|
40
|
+
is_expected.to eq '42'
|
41
|
+
end
|
42
|
+
end
|
43
|
+
context 'when the data attribute does not have an id value' do
|
44
|
+
let(:document) { { data: { type: 'examples' } } }
|
45
|
+
|
46
|
+
it { is_expected.to eq nil }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
context 'when the api document has string keys' do
|
50
|
+
context 'when the data attribute has an id value' do
|
51
|
+
let(:document) { { 'data' => { 'id' => '42', 'type' => 'examples' } } }
|
52
|
+
|
53
|
+
it 'returns the /data/id value' do
|
54
|
+
is_expected.to eq '42'
|
55
|
+
end
|
56
|
+
end
|
57
|
+
context 'when the data attribute does not have an id value' do
|
58
|
+
let(:document) { { 'data' => { 'type' => 'examples' } } }
|
59
|
+
|
60
|
+
it { is_expected.to eq nil }
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe '#resource_id' do
|
66
|
+
subject { instance.resource_id }
|
67
|
+
|
68
|
+
context 'when the deserializer#id_param is :id' do
|
69
|
+
before { allow(deserializer).to receive(:id_param).and_return(:id) }
|
70
|
+
|
71
|
+
it 'returns the resource id as a string' do
|
72
|
+
expect(resource).to receive(:id).and_return(42)
|
73
|
+
expect(subject).to eq '42'
|
74
|
+
end
|
75
|
+
end
|
76
|
+
context 'when the deserializer#id_param a field value' do
|
77
|
+
before { allow(deserializer).to receive(:id_param).and_return(:code) }
|
78
|
+
|
79
|
+
it 'returns the resource field value as a string' do
|
80
|
+
expect(resource).to receive(:code).and_return('foobar')
|
81
|
+
expect(subject).to eq 'foobar'
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe '#resource_type' do
|
87
|
+
subject { instance.resource_type }
|
88
|
+
|
89
|
+
it 'returns the deserializer type' do
|
90
|
+
expect(deserializer).to receive(:type).and_return('examples')
|
91
|
+
expect(subject).to eq 'examples'
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe FunWithJsonApi::SchemaValidators::CheckAttributes do
|
4
|
+
describe '.call' do
|
5
|
+
let(:document) do
|
6
|
+
{
|
7
|
+
'data' => {
|
8
|
+
'id' => '42',
|
9
|
+
'type' => 'examples',
|
10
|
+
'attributes' => {
|
11
|
+
'foobar' => 'blargh'
|
12
|
+
}
|
13
|
+
}
|
14
|
+
}
|
15
|
+
end
|
16
|
+
let(:deserializer) { instance_double('FunWithJsonApi::Deserializer', type: 'examples') }
|
17
|
+
subject { described_class.call(document, deserializer) }
|
18
|
+
|
19
|
+
context 'when the document contains an attribute supported by the deserializer' do
|
20
|
+
let(:attribute) { instance_double('FunWithJsonApi::Attribute', name: :foobar) }
|
21
|
+
before { allow(deserializer).to receive(:attributes).and_return([attribute]) }
|
22
|
+
|
23
|
+
it 'returns true' do
|
24
|
+
expect(subject).to eq true
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'when the document contains an unsupported attribute' do
|
29
|
+
before { allow(deserializer).to receive(:attributes).and_return([]) }
|
30
|
+
|
31
|
+
it 'raises a UnknownAttribute error' do
|
32
|
+
expect do
|
33
|
+
subject
|
34
|
+
end.to raise_error(FunWithJsonApi::Exceptions::UnknownAttribute) do |e|
|
35
|
+
expect(e.payload.size).to eq 1
|
36
|
+
|
37
|
+
payload = e.payload.first
|
38
|
+
expect(payload.code).to eq 'unknown_attribute'
|
39
|
+
expect(payload.pointer).to eq '/data/attributes/foobar'
|
40
|
+
expect(payload.title).to eq(
|
41
|
+
'Request json_api attribute is unsupported by the current endpoint'
|
42
|
+
)
|
43
|
+
expect(payload.detail).to eq(
|
44
|
+
"The provided attribute 'foobar' can not be assigned to a 'examples' resource"\
|
45
|
+
' from the current endpoint'
|
46
|
+
)
|
47
|
+
expect(payload.status).to eq '422'
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe FunWithJsonApi::SchemaValidators::CheckDocumentIdMatchesResource do
|
4
|
+
describe '.call' do
|
5
|
+
let(:schema_validator) do
|
6
|
+
instance_double('FunWithJsonApi::SchemaValidator', resource_type: 'examples')
|
7
|
+
end
|
8
|
+
subject { described_class.call(schema_validator) }
|
9
|
+
|
10
|
+
context 'when the resource is persisted' do
|
11
|
+
let(:resource) { instance_double('ActiveRecord::Base', persisted?: true) }
|
12
|
+
before { allow(schema_validator).to receive(:resource).and_return(resource) }
|
13
|
+
|
14
|
+
context 'when /data/id does not match the resource id' do
|
15
|
+
before do
|
16
|
+
allow(schema_validator).to receive(:resource_id).and_return('11')
|
17
|
+
allow(schema_validator).to receive(:document_id).and_return('42')
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'raises a InvalidDocumentIdentifier error' do
|
21
|
+
expect do
|
22
|
+
subject
|
23
|
+
end.to raise_error(FunWithJsonApi::Exceptions::InvalidDocumentIdentifier) do |e|
|
24
|
+
expect(e.payload.size).to eq 1
|
25
|
+
|
26
|
+
payload = e.payload.first
|
27
|
+
expect(payload.code).to eq 'invalid_document_identifier'
|
28
|
+
expect(payload.pointer).to eq '/data/id'
|
29
|
+
expect(payload.title).to eq 'Request json_api data id is invalid'
|
30
|
+
expect(payload.detail).to eq 'Expected data id to match resource at endpoint: 11'
|
31
|
+
expect(payload.status).to eq '409'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'when the resource is not persisted' do
|
38
|
+
let(:resource) { instance_double('ActiveRecord::Base', persisted?: false) }
|
39
|
+
before { allow(schema_validator).to receive(:resource).and_return(resource) }
|
40
|
+
|
41
|
+
context 'when a document_id has been supplied' do
|
42
|
+
before { allow(schema_validator).to receive(:document_id).and_return('42') }
|
43
|
+
|
44
|
+
context 'when the deserializer does not have an id attribute' do
|
45
|
+
let(:deserializer) { instance_double('FunWithJsonApi::Deserializer') }
|
46
|
+
before do
|
47
|
+
allow(schema_validator).to receive(:deserializer).and_return(deserializer)
|
48
|
+
allow(deserializer).to receive(:attributes).and_return([])
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'raises a IllegalClientGeneratedIdentifier error' do
|
52
|
+
expect do
|
53
|
+
subject
|
54
|
+
end.to raise_error(FunWithJsonApi::Exceptions::IllegalClientGeneratedIdentifier) do |e|
|
55
|
+
expect(e.payload.size).to eq 1
|
56
|
+
|
57
|
+
payload = e.payload.first
|
58
|
+
expect(payload.code).to eq 'illegal_client_generated_identifier'
|
59
|
+
expect(payload.pointer).to eq '/data/id'
|
60
|
+
expect(payload.title).to eq(
|
61
|
+
'Request json_api attempted to set an unsupported client-generated id'
|
62
|
+
)
|
63
|
+
expect(payload.detail).to eq(
|
64
|
+
"The current endpoint does not allow you to set an id for a new 'examples' resource"
|
65
|
+
)
|
66
|
+
expect(payload.status).to eq '403'
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
context 'when the deserializer has an id attribute' do
|
71
|
+
let(:deserializer) { instance_double('FunWithJsonApi::Deserializer') }
|
72
|
+
before do
|
73
|
+
allow(schema_validator).to receive(:deserializer).and_return(deserializer)
|
74
|
+
allow(deserializer).to receive(:attributes).and_return(
|
75
|
+
[
|
76
|
+
instance_double('FunWithJsonApi::Attribute', name: :id)
|
77
|
+
]
|
78
|
+
)
|
79
|
+
end
|
80
|
+
|
81
|
+
context 'when a resource matching id exists' do
|
82
|
+
before do
|
83
|
+
allow(deserializer).to receive(:load_resource_from_id_value)
|
84
|
+
.with('42')
|
85
|
+
.and_return(double('existing_resource', id: '24'))
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'raises a InvalidClientGeneratedIdentifier error' do
|
89
|
+
expect do
|
90
|
+
subject
|
91
|
+
end.to raise_error(
|
92
|
+
FunWithJsonApi::Exceptions::InvalidClientGeneratedIdentifier
|
93
|
+
) do |e|
|
94
|
+
expect(e.payload.size).to eq 1
|
95
|
+
|
96
|
+
payload = e.payload.first
|
97
|
+
expect(payload.code).to eq 'invalid_client_generated_identifier'
|
98
|
+
expect(payload.pointer).to eq '/data/id'
|
99
|
+
expect(payload.title).to eq(
|
100
|
+
'Request json_api data id has already been used for an existing'\
|
101
|
+
' resource'
|
102
|
+
)
|
103
|
+
expect(payload.detail).to eq(
|
104
|
+
"The provided id for a new 'examples' resource has already been used by another"\
|
105
|
+
' resource: 42'
|
106
|
+
)
|
107
|
+
expect(payload.status).to eq '409'
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe FunWithJsonApi::SchemaValidators::CheckDocumentTypeMatchesResource do
|
4
|
+
describe '.call' do
|
5
|
+
let(:schema_validator) do
|
6
|
+
instance_double('FunWithJsonApi::SchemaValidator')
|
7
|
+
end
|
8
|
+
subject { described_class.call(schema_validator) }
|
9
|
+
|
10
|
+
context 'when document_type does not match resource_type' do
|
11
|
+
before do
|
12
|
+
allow(schema_validator).to receive(:document_type).and_return('examples')
|
13
|
+
allow(schema_validator).to receive(:resource_type).and_return('foobar')
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'raises a InvalidDocumentType error' do
|
17
|
+
expect { subject }.to raise_error(FunWithJsonApi::Exceptions::InvalidDocumentType) do |e|
|
18
|
+
expect(e.payload.size).to eq 1
|
19
|
+
|
20
|
+
payload = e.payload.first
|
21
|
+
expect(payload.code).to eq 'invalid_document_type'
|
22
|
+
expect(payload.pointer).to eq '/data/type'
|
23
|
+
expect(payload.title).to eq 'Request json_api data type does not match endpoint'
|
24
|
+
expect(payload.detail).to eq "Expected data type to be a 'foobar' resource"
|
25
|
+
expect(payload.status).to eq '409'
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,150 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe FunWithJsonApi::SchemaValidators::CheckRelationships do
|
4
|
+
describe '.call' do
|
5
|
+
let(:document) do
|
6
|
+
{
|
7
|
+
'data' => {
|
8
|
+
'id' => '42',
|
9
|
+
'type' => 'examples',
|
10
|
+
'relationships' => {
|
11
|
+
'foobar' => {
|
12
|
+
'data' => relationship_data
|
13
|
+
}
|
14
|
+
}
|
15
|
+
}
|
16
|
+
}
|
17
|
+
end
|
18
|
+
let(:relationship_data) { double('relationship_data') }
|
19
|
+
let(:deserializer) { instance_double('FunWithJsonApi::Deserializer', type: 'examples') }
|
20
|
+
subject { described_class.call(document, deserializer) }
|
21
|
+
|
22
|
+
context 'with a has-one relationship' do
|
23
|
+
let(:relationship) do
|
24
|
+
instance_double('FunWithJsonApi::Relationship', name: :foobar, has_many?: false)
|
25
|
+
end
|
26
|
+
before { allow(deserializer).to receive(:relationships).and_return([relationship]) }
|
27
|
+
|
28
|
+
context 'when the relationship item is a hash' do
|
29
|
+
let(:relationship_data) { { 'id' => '24', 'type' => 'foobars' } }
|
30
|
+
|
31
|
+
context 'when the type matches the relationship' do
|
32
|
+
before { allow(relationship).to receive(:type).and_return('foobars') }
|
33
|
+
|
34
|
+
it { is_expected.to eq true }
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'when the type does not match the relationship' do
|
38
|
+
before { allow(relationship).to receive(:type).and_return('invalid') }
|
39
|
+
|
40
|
+
it 'raises a InvalidRelationshipType error' do
|
41
|
+
expect do
|
42
|
+
subject
|
43
|
+
end.to raise_error(FunWithJsonApi::Exceptions::InvalidRelationshipType) do |e|
|
44
|
+
expect(e.payload.size).to eq 1
|
45
|
+
|
46
|
+
payload = e.payload.first
|
47
|
+
expect(payload.code).to eq 'invalid_relationship_type'
|
48
|
+
expect(payload.pointer).to eq '/data/relationships/foobar/type'
|
49
|
+
expect(payload.title).to eq(
|
50
|
+
'Request json_api relationship type does not match expected resource'
|
51
|
+
)
|
52
|
+
expect(payload.detail).to eq(
|
53
|
+
"Expected 'foobar' relationship to be null or a 'invalid' resource identifier Hash"
|
54
|
+
)
|
55
|
+
expect(payload.status).to eq '409'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'when the relationship item is nil' do
|
62
|
+
let(:relationship_data) { nil }
|
63
|
+
|
64
|
+
it { is_expected.to eq true }
|
65
|
+
end
|
66
|
+
|
67
|
+
context 'when the relationship item is a array' do
|
68
|
+
let(:relationship_data) { [{ 'id' => '24', 'type' => 'foobars' }] }
|
69
|
+
|
70
|
+
it { is_expected.to eq true }
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context 'with a has-many relationship' do
|
75
|
+
let(:relationship) do
|
76
|
+
instance_double('FunWithJsonApi::RelationshipCollection', name: :foobar, has_many?: true)
|
77
|
+
end
|
78
|
+
before { allow(deserializer).to receive(:relationships).and_return([relationship]) }
|
79
|
+
|
80
|
+
context 'when the relationship item is a array' do
|
81
|
+
let(:relationship_data) { [{ 'id' => '24', 'type' => 'foobars' }] }
|
82
|
+
|
83
|
+
context 'when the type matches the relationship' do
|
84
|
+
before { allow(relationship).to receive(:type).and_return('foobars') }
|
85
|
+
|
86
|
+
it { is_expected.to eq true }
|
87
|
+
end
|
88
|
+
|
89
|
+
context 'when the type does not match the deserializer' do
|
90
|
+
before { allow(relationship).to receive(:type).and_return('invalid') }
|
91
|
+
|
92
|
+
it 'raises a InvalidRelationshipType error' do
|
93
|
+
expect do
|
94
|
+
subject
|
95
|
+
end.to raise_error(FunWithJsonApi::Exceptions::InvalidRelationshipType) do |e|
|
96
|
+
expect(e.payload.size).to eq 1
|
97
|
+
|
98
|
+
payload = e.payload.first
|
99
|
+
expect(payload.code).to eq 'invalid_relationship_type'
|
100
|
+
expect(payload.pointer).to eq '/data/relationships/foobar/0/type'
|
101
|
+
expect(payload.title).to eq(
|
102
|
+
'Request json_api relationship type does not match expected resource'
|
103
|
+
)
|
104
|
+
expect(payload.detail).to eq(
|
105
|
+
"Expected 'foobar' relationship to be an Array of 'invalid' resource identifiers"
|
106
|
+
)
|
107
|
+
expect(payload.status).to eq '409'
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
context 'when the relationship item is a hash' do
|
114
|
+
let(:relationship_data) { { 'id' => '24', 'type' => 'foobars' } }
|
115
|
+
|
116
|
+
it { is_expected.to eq true }
|
117
|
+
end
|
118
|
+
|
119
|
+
context 'when the relationship item is nil' do
|
120
|
+
let(:relationship_data) { nil }
|
121
|
+
|
122
|
+
it { is_expected.to eq true }
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
context 'when the document contains an unsupported relationships' do
|
127
|
+
before { allow(deserializer).to receive(:relationships).and_return([]) }
|
128
|
+
|
129
|
+
it 'raises a UnknownRelationship error' do
|
130
|
+
expect do
|
131
|
+
subject
|
132
|
+
end.to raise_error(FunWithJsonApi::Exceptions::UnknownRelationship) do |e|
|
133
|
+
expect(e.payload.size).to eq 1
|
134
|
+
|
135
|
+
payload = e.payload.first
|
136
|
+
expect(payload.code).to eq 'unknown_relationship'
|
137
|
+
expect(payload.pointer).to eq '/data/relationships/foobar'
|
138
|
+
expect(payload.title).to eq(
|
139
|
+
'Request json_api relationship is unsupported by the current endpoint'
|
140
|
+
)
|
141
|
+
expect(payload.detail).to eq(
|
142
|
+
"The provided relationship 'foobar' can not be assigned to a 'examples' resource"\
|
143
|
+
' from the current endpoint'
|
144
|
+
)
|
145
|
+
expect(payload.status).to eq '422'
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|