fun_with_json_api 0.0.1

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.
Files changed (76) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/Rakefile +28 -0
  4. data/config/locales/fun_with_json_api.en.yml +13 -0
  5. data/lib/fun_with_json_api/attribute.rb +38 -0
  6. data/lib/fun_with_json_api/attributes/boolean_attribute.rb +24 -0
  7. data/lib/fun_with_json_api/attributes/date_attribute.rb +22 -0
  8. data/lib/fun_with_json_api/attributes/datetime_attribute.rb +20 -0
  9. data/lib/fun_with_json_api/attributes/decimal_attribute.rb +23 -0
  10. data/lib/fun_with_json_api/attributes/float_attribute.rb +20 -0
  11. data/lib/fun_with_json_api/attributes/integer_attribute.rb +20 -0
  12. data/lib/fun_with_json_api/attributes/relationship.rb +73 -0
  13. data/lib/fun_with_json_api/attributes/relationship_collection.rb +99 -0
  14. data/lib/fun_with_json_api/attributes/string_attribute.rb +9 -0
  15. data/lib/fun_with_json_api/controller_methods.rb +12 -0
  16. data/lib/fun_with_json_api/deserializer.rb +70 -0
  17. data/lib/fun_with_json_api/deserializer_class_methods.rb +83 -0
  18. data/lib/fun_with_json_api/deserializer_config_builder.rb +48 -0
  19. data/lib/fun_with_json_api/exception.rb +27 -0
  20. data/lib/fun_with_json_api/exception_payload.rb +29 -0
  21. data/lib/fun_with_json_api/exception_payload_serializer.rb +17 -0
  22. data/lib/fun_with_json_api/exception_serializer.rb +15 -0
  23. data/lib/fun_with_json_api/exceptions/invalid_attribute.rb +13 -0
  24. data/lib/fun_with_json_api/exceptions/invalid_document.rb +12 -0
  25. data/lib/fun_with_json_api/exceptions/invalid_relationship.rb +13 -0
  26. data/lib/fun_with_json_api/exceptions/missing_relationship.rb +15 -0
  27. data/lib/fun_with_json_api/pre_deserializer.rb +61 -0
  28. data/lib/fun_with_json_api/railtie.rb +11 -0
  29. data/lib/fun_with_json_api/version.rb +3 -0
  30. data/lib/fun_with_json_api.rb +24 -0
  31. data/lib/tasks/fun_with_json_api_tasks.rake +4 -0
  32. data/spec/dummy/README.rdoc +28 -0
  33. data/spec/dummy/Rakefile +6 -0
  34. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  35. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  36. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  37. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  38. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  39. data/spec/dummy/bin/bundle +3 -0
  40. data/spec/dummy/bin/rails +4 -0
  41. data/spec/dummy/bin/rake +4 -0
  42. data/spec/dummy/bin/setup +29 -0
  43. data/spec/dummy/config/application.rb +25 -0
  44. data/spec/dummy/config/boot.rb +5 -0
  45. data/spec/dummy/config/database.yml +25 -0
  46. data/spec/dummy/config/environment.rb +5 -0
  47. data/spec/dummy/config/environments/development.rb +41 -0
  48. data/spec/dummy/config/environments/production.rb +80 -0
  49. data/spec/dummy/config/environments/test.rb +42 -0
  50. data/spec/dummy/config/initializers/assets.rb +11 -0
  51. data/spec/dummy/config/initializers/backtrace_silencers.rb +9 -0
  52. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
  53. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  54. data/spec/dummy/config/initializers/inflections.rb +16 -0
  55. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  56. data/spec/dummy/config/initializers/session_store.rb +3 -0
  57. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  58. data/spec/dummy/config/locales/en.yml +23 -0
  59. data/spec/dummy/config/routes.rb +56 -0
  60. data/spec/dummy/config/secrets.yml +22 -0
  61. data/spec/dummy/config.ru +4 -0
  62. data/spec/dummy/log/test.log +37839 -0
  63. data/spec/dummy/public/404.html +67 -0
  64. data/spec/dummy/public/422.html +67 -0
  65. data/spec/dummy/public/500.html +66 -0
  66. data/spec/dummy/public/favicon.ico +0 -0
  67. data/spec/example_spec.rb +64 -0
  68. data/spec/fixtures/active_record.rb +65 -0
  69. data/spec/fun_with_json_api/controller_methods_spec.rb +123 -0
  70. data/spec/fun_with_json_api/deserializer_class_methods_spec.rb +52 -0
  71. data/spec/fun_with_json_api/deserializer_spec.rb +450 -0
  72. data/spec/fun_with_json_api/exception_spec.rb +77 -0
  73. data/spec/fun_with_json_api/pre_deserializer_spec.rb +287 -0
  74. data/spec/fun_with_json_api_spec.rb +55 -0
  75. data/spec/spec_helper.rb +33 -0
  76. metadata +275 -0
@@ -0,0 +1,52 @@
1
+ require 'spec_helper'
2
+
3
+ describe FunWithJsonApi::DeserializerClassMethods do
4
+ describe '.belongs_to' do
5
+ it 'should add a Relationship attribute' do
6
+ foos_deserializer_class = Class.new(FunWithJsonApi::Deserializer) do
7
+ attribute :blargh
8
+ end
9
+ deserializer_class = Class.new(FunWithJsonApi::Deserializer) do
10
+ belongs_to :foo, -> { foos_deserializer_class }
11
+ end
12
+ relationship = deserializer_class.relationships.last
13
+ expect(relationship).to be_kind_of(FunWithJsonApi::Attributes::Relationship)
14
+
15
+ expect(relationship.name).to eq :foo
16
+ expect(relationship.as).to eq :foo
17
+ expect(relationship.deserializer).to be_kind_of(foos_deserializer_class)
18
+
19
+ expect(relationship.deserializer.attributes).to eq []
20
+ expect(relationship.deserializer.relationships).to eq []
21
+ end
22
+ end
23
+
24
+ describe '.has_many' do
25
+ it 'should add a RelationshipCollection attribute' do
26
+ foos_deserializer_class = Class.new(FunWithJsonApi::Deserializer) do
27
+ attribute :blargh
28
+ end
29
+ deserializer_class = Class.new(FunWithJsonApi::Deserializer) do
30
+ has_many :foos, -> { foos_deserializer_class }
31
+ end
32
+ relationship = deserializer_class.relationships.last
33
+ expect(relationship).to be_kind_of(FunWithJsonApi::Attributes::RelationshipCollection)
34
+
35
+ expect(relationship.name).to eq :foos
36
+ expect(relationship.as).to eq :foo
37
+ expect(relationship.deserializer).to be_kind_of(foos_deserializer_class)
38
+
39
+ expect(relationship.deserializer.attributes).to eq []
40
+ expect(relationship.deserializer.relationships).to eq []
41
+ end
42
+
43
+ it 'should not allow pluralized as values' do
44
+ foos_deserializer_class = Class.new(FunWithJsonApi::Deserializer)
45
+ expect do
46
+ Class.new(FunWithJsonApi::Deserializer) do
47
+ has_many :foos, -> { foos_deserializer_class }, as: 'foos'
48
+ end
49
+ end.to raise_error(ArgumentError, 'Use a singular relationship as value: {as: :foo}')
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,450 @@
1
+ require 'spec_helper'
2
+
3
+ # Returns a FunWithJsonApi::Deserializer class with an attribute
4
+ #
5
+ # Equivalent of:
6
+ # ```
7
+ # class ExampleDeserializer < FunWithJsonApi::Deserializer
8
+ # attribute #{attribute}, #{attribute_options}
9
+ # end
10
+ def deserializer_class_with_attribute(attribute, attribute_options = {})
11
+ Class.new(FunWithJsonApi::Deserializer) do
12
+ attribute attribute, attribute_options
13
+ end
14
+ end
15
+
16
+ def deserializer_class_with_relationship(relationship, relationship_type, relationship_options = {})
17
+ relationship_deserializer = Class.new(FunWithJsonApi::Deserializer) do
18
+ type(relationship_type)
19
+ end
20
+
21
+ Class.new(FunWithJsonApi::Deserializer) do
22
+ belongs_to relationship, relationship_deserializer, relationship_options
23
+ end
24
+ end
25
+
26
+ # Returns an instance of a FunWithJsonApi::Deserializer with an attribute with an assigned value
27
+ #
28
+ # Equivalent of:
29
+ # ```
30
+ # class ExampleDeserializer < FunWithJsonApi::Deserializer
31
+ # attribute #{attribute}, #{attribute_options}
32
+ # end
33
+ # ExampleDeserializer.create
34
+ # ~~~
35
+ def deserializer_with_attribute(attribute, attribute_options = {})
36
+ deserializer_class_with_attribute(attribute, attribute_options).create
37
+ end
38
+
39
+ describe FunWithJsonApi::Deserializer do
40
+ describe '#parse_{attribute}' do
41
+ context 'with an alias value' do
42
+ it 'should generated an attribute from the alias value' do
43
+ deserializer = deserializer_with_attribute(:original_key, as: :assigned_key)
44
+ expect(deserializer.parse_assigned_key('Foo Bar')).to eq 'Foo Bar'
45
+ expect(deserializer).to_not respond_to(:original_key)
46
+ end
47
+ end
48
+
49
+ context 'with no format argument (string)' do
50
+ it 'should allow a String value' do
51
+ deserializer = deserializer_with_attribute(:example)
52
+ expect(deserializer.parse_example('Foo Bar')).to eq 'Foo Bar'
53
+ end
54
+ it 'should allow a nil value' do
55
+ deserializer = deserializer_with_attribute(:example)
56
+ expect(deserializer.parse_example(nil)).to be nil
57
+ end
58
+ end
59
+
60
+ context 'with a boolean format' do
61
+ it 'should allow a Boolean.TRUE value' do
62
+ deserializer = deserializer_with_attribute(:example, format: :boolean)
63
+ expect(deserializer.parse_example(true)).to eq true
64
+ end
65
+ it 'should allow a Boolean.FALSE value' do
66
+ deserializer = deserializer_with_attribute(:example, format: :boolean)
67
+ expect(deserializer.parse_example(false)).to eq false
68
+ end
69
+ it 'should allow a nil value' do
70
+ deserializer = deserializer_with_attribute(:example, format: :boolean)
71
+ expect(deserializer.parse_example(nil)).to be nil
72
+ end
73
+ it 'should raise an InvalidAttribute for invalid boolean values' do
74
+ deserializer = deserializer_with_attribute(:example, format: :boolean)
75
+ ['true', 'True', 'TRUE', 1, 'false', 'False', 'FALSE', 0].each do |value|
76
+ expect do
77
+ deserializer.parse_example(value)
78
+ end.to raise_error(FunWithJsonApi::Exceptions::InvalidAttribute) do |e|
79
+ expect(e.payload.size).to eq 1
80
+
81
+ payload = e.payload.first
82
+ expect(payload.status).to eq '400'
83
+ expect(payload.code).to eq 'invalid_attribute'
84
+ expect(payload.title).to eq(
85
+ I18n.t('fun_with_json_api.exceptions.invalid_attribute')
86
+ )
87
+ expect(payload.detail).to eq(
88
+ I18n.t('fun_with_json_api.exceptions.invalid_boolean_attribute')
89
+ )
90
+ expect(payload.pointer).to eq '/data/attributes/example'
91
+ end
92
+ end
93
+ end
94
+ end
95
+
96
+ context 'with a date format' do
97
+ it 'should allow a "YYYY-MM-DD" formatted value' do
98
+ deserializer = deserializer_with_attribute(:example, format: :date)
99
+ expect(deserializer.parse_example('2016-03-12')).to eq Date.new(2016, 03, 12)
100
+ end
101
+ it 'should allow a nil value' do
102
+ deserializer = deserializer_with_attribute(:example, format: :date)
103
+ expect(deserializer.parse_example(nil)).to be nil
104
+ end
105
+ it 'should raise an InvalidAttribute for invalid date value' do
106
+ deserializer = deserializer_with_attribute(:example, format: :date)
107
+ ['2016-12', 'Last Wednesday', 'April'].each do |value|
108
+ expect do
109
+ deserializer.parse_example(value)
110
+ end.to raise_error(FunWithJsonApi::Exceptions::InvalidAttribute) do |e|
111
+ expect(e.payload.size).to eq 1
112
+
113
+ payload = e.payload.first
114
+ expect(payload.status).to eq '400'
115
+ expect(payload.code).to eq 'invalid_attribute'
116
+ expect(payload.title).to eq(
117
+ I18n.t('fun_with_json_api.exceptions.invalid_attribute')
118
+ )
119
+ expect(payload.detail).to eq(
120
+ I18n.t('fun_with_json_api.exceptions.invalid_date_attribute')
121
+ )
122
+ expect(payload.pointer).to eq '/data/attributes/example'
123
+ end
124
+ end
125
+ end
126
+ end
127
+
128
+ context 'with a datetime format' do
129
+ it 'should allow a ISO 8601 formatted values' do
130
+ deserializer = deserializer_with_attribute(:example, format: :datetime)
131
+ [
132
+ '2016-03-11T03:45:40+00:00',
133
+ '2016-03-11T13:45:40+10:00',
134
+ '2016-03-11T03:45:40Z',
135
+ '20160311T034540Z'
136
+ ].each do |timestamp|
137
+ expect(deserializer.parse_example(timestamp)).to eq(
138
+ DateTime.new(2016, 03, 11, 3, 45, 40, 0)
139
+ )
140
+ end
141
+ end
142
+ it 'should allow a nil value' do
143
+ deserializer = deserializer_with_attribute(:example, format: :datetime)
144
+ expect(deserializer.parse_example(nil)).to be nil
145
+ end
146
+ it 'should raise an InvalidAttribute for invalid date value' do
147
+ deserializer = deserializer_with_attribute(:example, format: :datetime)
148
+ [
149
+ 'Last Wednesday',
150
+ 'April'
151
+ ].each do |value|
152
+ expect do
153
+ deserializer.parse_example(value)
154
+ end.to raise_error(FunWithJsonApi::Exceptions::InvalidAttribute) do |e|
155
+ expect(e.payload.size).to eq 1
156
+
157
+ payload = e.payload.first
158
+ expect(payload.status).to eq '400'
159
+ expect(payload.code).to eq 'invalid_attribute'
160
+ expect(payload.title).to eq(
161
+ I18n.t('fun_with_json_api.exceptions.invalid_attribute')
162
+ )
163
+ expect(payload.detail).to eq(
164
+ I18n.t('fun_with_json_api.exceptions.invalid_datetime_attribute')
165
+ )
166
+ expect(payload.pointer).to eq '/data/attributes/example'
167
+ end
168
+ end
169
+ end
170
+ end
171
+
172
+ context 'with a decimal format' do
173
+ it 'should allow integers' do
174
+ deserializer = deserializer_with_attribute(:example, format: :decimal)
175
+ expect(deserializer.parse_example(12)).to eq BigDecimal.new('12')
176
+ end
177
+ it 'should allow floats' do
178
+ deserializer = deserializer_with_attribute(:example, format: :decimal)
179
+ expect(deserializer.parse_example(12.34)).to eq BigDecimal.new('12.34')
180
+ end
181
+ it 'should allow integer numbers as strings' do
182
+ deserializer = deserializer_with_attribute(:example, format: :decimal)
183
+ expect(deserializer.parse_example('12')).to eq BigDecimal.new('12')
184
+ end
185
+ it 'should allow floating point numbers as strings' do
186
+ deserializer = deserializer_with_attribute(:example, format: :decimal)
187
+ expect(deserializer.parse_example('12.30')).to eq BigDecimal.new('12.30')
188
+ end
189
+ it 'should allow a nil value' do
190
+ deserializer = deserializer_with_attribute(:example, format: :decimal)
191
+ expect(deserializer.parse_example(nil)).to be nil
192
+ end
193
+ it 'should raise an InvalidAttribute for invalid decimal value' do
194
+ deserializer = deserializer_with_attribute(:example, format: :decimal)
195
+ [
196
+ 'twelve',
197
+ '-',
198
+ 'abc'
199
+ ].each do |value|
200
+ expect do
201
+ deserializer.parse_example(value)
202
+ end.to raise_error(FunWithJsonApi::Exceptions::InvalidAttribute) do |e|
203
+ expect(e.payload.size).to eq 1
204
+
205
+ payload = e.payload.first
206
+ expect(payload.status).to eq '400'
207
+ expect(payload.code).to eq 'invalid_attribute'
208
+ expect(payload.title).to eq(
209
+ I18n.t('fun_with_json_api.exceptions.invalid_attribute')
210
+ )
211
+ expect(payload.detail).to eq(
212
+ I18n.t('fun_with_json_api.exceptions.invalid_decimal_attribute')
213
+ )
214
+ expect(payload.pointer).to eq '/data/attributes/example'
215
+ end
216
+ end
217
+ end
218
+ end
219
+
220
+ context 'with a float format' do
221
+ it 'should allow floats' do
222
+ deserializer = deserializer_with_attribute(:example, format: :float)
223
+ expect(deserializer.parse_example(12.34)).to eq 12.34
224
+ end
225
+ it 'should allow float numbers as strings' do
226
+ deserializer = deserializer_with_attribute(:example, format: :float)
227
+ expect(deserializer.parse_example('12.34')).to eq 12.34
228
+ end
229
+ it 'should allow integer numbers as strings' do
230
+ deserializer = deserializer_with_attribute(:example, format: :float)
231
+ expect(deserializer.parse_example('12')).to eq 12.0
232
+ end
233
+ it 'should allow a nil value' do
234
+ deserializer = deserializer_with_attribute(:example, format: :float)
235
+ expect(deserializer.parse_example(nil)).to be nil
236
+ end
237
+ it 'should raise an InvalidAttribute for invalid float value' do
238
+ deserializer = deserializer_with_attribute(:example, format: :float)
239
+ [
240
+ 'twelve',
241
+ '-',
242
+ 'abc'
243
+ ].each do |value|
244
+ expect do
245
+ deserializer.parse_example(value)
246
+ end.to raise_error(FunWithJsonApi::Exceptions::InvalidAttribute) do |e|
247
+ expect(e.payload.size).to eq 1
248
+
249
+ payload = e.payload.first
250
+ expect(payload.status).to eq '400'
251
+ expect(payload.code).to eq 'invalid_attribute'
252
+ expect(payload.title).to eq(
253
+ I18n.t('fun_with_json_api.exceptions.invalid_attribute')
254
+ )
255
+ expect(payload.detail).to eq(
256
+ I18n.t('fun_with_json_api.exceptions.invalid_float_attribute')
257
+ )
258
+ expect(payload.pointer).to eq '/data/attributes/example'
259
+ end
260
+ end
261
+ end
262
+ end
263
+
264
+ context 'with a integer format' do
265
+ it 'should allow integer numbers as strings' do
266
+ deserializer = deserializer_with_attribute(:example, format: :integer)
267
+ expect(deserializer.parse_example('12')).to eq BigDecimal.new('12')
268
+ end
269
+ it 'should allow a nil value' do
270
+ deserializer = deserializer_with_attribute(:example, format: :integer)
271
+ expect(deserializer.parse_example(nil)).to be nil
272
+ end
273
+ it 'should raise an InvalidAttribute for invalid integer value' do
274
+ deserializer = deserializer_with_attribute(:example, format: :integer)
275
+ [
276
+ 12.0,
277
+ '12.0',
278
+ 'twelve',
279
+ '-',
280
+ 'abc'
281
+ ].each do |value|
282
+ expect do
283
+ deserializer.parse_example(value)
284
+ end.to raise_error(FunWithJsonApi::Exceptions::InvalidAttribute) do |e|
285
+ expect(e.payload.size).to eq 1
286
+
287
+ payload = e.payload.first
288
+ expect(payload.status).to eq '400'
289
+ expect(payload.code).to eq 'invalid_attribute'
290
+ expect(payload.title).to eq(
291
+ I18n.t('fun_with_json_api.exceptions.invalid_attribute')
292
+ )
293
+ expect(payload.detail).to eq(
294
+ I18n.t('fun_with_json_api.exceptions.invalid_integer_attribute')
295
+ )
296
+ expect(payload.pointer).to eq '/data/attributes/example'
297
+ end
298
+ end
299
+ end
300
+ end
301
+
302
+ it 'raises an ArgumentError with an unknown format' do
303
+ expect do
304
+ deserializer_class_with_attribute(:example, format: :blarg)
305
+ end.to raise_error(ArgumentError)
306
+ end
307
+
308
+ it 'raises an ArgumentError with a blank attribute name' do
309
+ expect do
310
+ deserializer_class_with_attribute('', format: :string)
311
+ end.to raise_error(ArgumentError)
312
+ end
313
+ end
314
+
315
+ describe '#parse_{relationship}_id' do
316
+ context 'with a ARModels::Author relationship with a "code" id param' do
317
+ let(:deserializer) do
318
+ author_deserializer_class = Class.new(FunWithJsonApi::Deserializer) do
319
+ id_param 'code'
320
+ type 'persons'
321
+ resource_class ARModels::Author
322
+ end
323
+
324
+ # Build the Deserializer
325
+ Class.new(FunWithJsonApi::Deserializer) do
326
+ belongs_to :example, author_deserializer_class
327
+ end.create
328
+ end
329
+
330
+ it 'finds a resource by the defined id_param and returns the resource id' do
331
+ author = ARModels::Author.create(id: 1, code: 'foobar')
332
+ expect(deserializer.parse_example_id('foobar')).to eq author.id
333
+ end
334
+
335
+ it 'raises a MissingRelationship when unable to find the resource' do
336
+ expect do
337
+ deserializer.parse_example_id 'foobar'
338
+ end.to raise_error(FunWithJsonApi::Exceptions::MissingRelationship) do |e|
339
+ expect(e.message).to start_with "Couldn't find ARModels::Author where code = \"foobar\": "
340
+ expect(e.payload.size).to eq 1
341
+
342
+ payload = e.payload.first
343
+ expect(payload.status).to eq '404'
344
+ expect(payload.code).to eq 'missing_relationship'
345
+ expect(payload.title).to eq I18n.t('fun_with_json_api.exceptions.missing_relationship')
346
+ expect(payload.pointer).to eq '/data/relationships/example/id'
347
+ expect(payload.detail).to eq "Unable to find 'persons' with matching id: \"foobar\""
348
+ end
349
+ end
350
+
351
+ it 'raises a InvalidRelationship when given an array value' do
352
+ expect do
353
+ deserializer.parse_example_id %w(1 2)
354
+ end.to raise_error(FunWithJsonApi::Exceptions::InvalidRelationship) do |e|
355
+ expect(e.payload.size).to eq 1
356
+
357
+ payload = e.payload.first
358
+ expect(payload.status).to eq '400'
359
+ expect(payload.code).to eq 'invalid_relationship'
360
+ expect(payload.title).to eq I18n.t('fun_with_json_api.exceptions.invalid_relationship')
361
+ expect(payload.pointer).to eq '/data/relationships/example'
362
+ expect(payload.detail).to be_kind_of(String)
363
+ end
364
+ end
365
+ end
366
+ end
367
+
368
+ describe '#parse_{relationship}_ids' do
369
+ context 'with a ARModels::Author relationship with a "code" id param' do
370
+ let(:deserializer) do
371
+ author_deserializer_class = Class.new(FunWithJsonApi::Deserializer) do
372
+ id_param 'code'
373
+ type 'persons'
374
+ resource_class ARModels::Author
375
+ end
376
+
377
+ # Build the Deserializer
378
+ Class.new(FunWithJsonApi::Deserializer) do
379
+ has_many :examples, author_deserializer_class
380
+ end.create
381
+ end
382
+
383
+ it 'finds a resource by the defined id_param and returns the resource id' do
384
+ author_a = ARModels::Author.create(id: 1, code: 'foobar')
385
+ author_b = ARModels::Author.create(id: 2, code: 'blargh')
386
+ expect(deserializer.parse_example_ids(%w(foobar blargh))).to eq(
387
+ [author_a.id, author_b.id]
388
+ )
389
+ end
390
+
391
+ it 'raises a MissingRelationship when unable to find a single resource' do
392
+ ARModels::Author.create(id: 1, code: 'foobar')
393
+
394
+ expect do
395
+ deserializer.parse_example_ids %w(foobar blargh)
396
+ end.to raise_error(FunWithJsonApi::Exceptions::MissingRelationship) do |e|
397
+ expect(e.message).to eq "Couldn't find ARModels::Author items with code in [\"blargh\"]"
398
+ expect(e.payload.size).to eq 1
399
+
400
+ payload = e.payload.first
401
+ expect(payload.status).to eq '404'
402
+ expect(payload.code).to eq 'missing_relationship'
403
+ expect(payload.title).to eq I18n.t('fun_with_json_api.exceptions.missing_relationship')
404
+ expect(payload.pointer).to eq '/data/relationships/examples/id'
405
+ expect(payload.detail).to eq "Unable to find 'persons' with matching id: \"blargh\""
406
+ end
407
+ end
408
+
409
+ it 'raises a MissingRelationship with a payload for all missing resources' do
410
+ expect do
411
+ deserializer.parse_example_ids %w(foobar blargh)
412
+ end.to raise_error(FunWithJsonApi::Exceptions::MissingRelationship) do |e|
413
+ expect(e.message).to eq(
414
+ "Couldn't find ARModels::Author items with code in [\"foobar\", \"blargh\"]"
415
+ )
416
+ expect(e.payload.size).to eq 2
417
+
418
+ payload_a = e.payload.first
419
+ expect(payload_a.status).to eq '404'
420
+ expect(payload_a.code).to eq 'missing_relationship'
421
+ expect(payload_a.title).to eq I18n.t('fun_with_json_api.exceptions.missing_relationship')
422
+ expect(payload_a.pointer).to eq '/data/relationships/examples/id'
423
+ expect(payload_a.detail).to eq "Unable to find 'persons' with matching id: \"foobar\""
424
+
425
+ payload_b = e.payload.last
426
+ expect(payload_b.status).to eq '404'
427
+ expect(payload_b.code).to eq 'missing_relationship'
428
+ expect(payload_b.title).to eq I18n.t('fun_with_json_api.exceptions.missing_relationship')
429
+ expect(payload_b.pointer).to eq '/data/relationships/examples/id'
430
+ expect(payload_b.detail).to eq "Unable to find 'persons' with matching id: \"blargh\""
431
+ end
432
+ end
433
+
434
+ it 'raises a InvalidRelationship when given a non-array value' do
435
+ expect do
436
+ deserializer.parse_example_ids '1'
437
+ end.to raise_error(FunWithJsonApi::Exceptions::InvalidRelationship) do |e|
438
+ expect(e.payload.size).to eq 1
439
+
440
+ payload = e.payload.first
441
+ expect(payload.status).to eq '400'
442
+ expect(payload.code).to eq 'invalid_relationship'
443
+ expect(payload.title).to eq I18n.t('fun_with_json_api.exceptions.invalid_relationship')
444
+ expect(payload.pointer).to eq '/data/relationships/examples'
445
+ expect(payload.detail).to be_kind_of(String)
446
+ end
447
+ end
448
+ end
449
+ end
450
+ end