ivy-serializers 0.3.0 → 0.4.0
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/.travis.yml +3 -2
- data/CHANGELOG.md +34 -0
- data/ivy-serializers.gemspec +4 -3
- data/lib/ivy/serializers/documents/document.rb +1 -1
- data/lib/ivy/serializers/formats/active_model_serializers.rb +2 -2
- data/lib/ivy/serializers/formats/json.rb +9 -7
- data/lib/ivy/serializers/formats/json_api.rb +5 -1
- data/lib/ivy/serializers/mapping.rb +4 -4
- data/lib/ivy/serializers/version.rb +1 -1
- data/spec/integration/formats/json_api_spec.rb +68 -24
- data/spec/schemas/json_api.json +375 -0
- data/spec/spec_helper.rb +9 -0
- metadata +32 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c4f730c6f599627a61aa2d51d349ac7bfa0b893a
|
4
|
+
data.tar.gz: e2b0e59978d005a5ffc7decb845f8d782965d061
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eb1814bce93d75c634a8ef055c7ea494c5d665a379a3ba0abcf790b0aece91b2f8b8dc68ed12f330c4aca260de48b3f55d49659362d589eaae91fc23a8909ae6
|
7
|
+
data.tar.gz: 4aee5deab59fcf959d77f46fb9c8cd928c78c6d6fbaaa699b67e4a40fd9bcf33055c16c4bb8b2f5f95ce9b0bf789d9d280eeae086628e643fa61582a5921a01a
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# ivy-serializers
|
2
|
+
|
3
|
+
See [changes since release][HEAD]
|
4
|
+
|
5
|
+
## [0.4.0][] / 2016-11-12
|
6
|
+
|
7
|
+
* Drop Ruby 1.9 support.
|
8
|
+
* Remove `activesupport` dependency in favor of `inflecto`.
|
9
|
+
* Change `included` into an array, per the JSON-API spec.
|
10
|
+
|
11
|
+
## [0.3.0][] / 2015-06-05
|
12
|
+
|
13
|
+
* Gracefully handle `nil` in belongs-to relationships.
|
14
|
+
* Update JSON-API format for 1.0.
|
15
|
+
* Always include an `id` attribute for all resources, per JSON-API spec.
|
16
|
+
|
17
|
+
## [0.2.0][] / 2015-05-05
|
18
|
+
|
19
|
+
* Fixes a bug where the JSON-API format wouldn't use the `:data` key as the
|
20
|
+
top-level when rendering a collection, and ensures that the
|
21
|
+
`ActiveModel::Serializers` format uses a singular key when rendering an
|
22
|
+
individual resource.
|
23
|
+
* Extract Rails integration into [ivy-serializers-rails][].
|
24
|
+
|
25
|
+
## [0.1.0][] / 2015-05-01
|
26
|
+
|
27
|
+
* Initial release.
|
28
|
+
|
29
|
+
[0.1.0]: https://github.com/IvyApp/ivy-serializers/tree/v0.1.0
|
30
|
+
[0.2.0]: https://github.com/IvyApp/ivy-serializers/compare/v0.1.0...v0.2.0
|
31
|
+
[0.3.0]: https://github.com/IvyApp/ivy-serializers/compare/v0.2.0...v0.3.0
|
32
|
+
[0.4.0]: https://github.com/IvyApp/ivy-serializers/compare/v0.3.0...v0.4.0
|
33
|
+
[HEAD]: https://github.com/IvyApp/ivy-serializers/compare/v0.4.0...master
|
34
|
+
[ivy-serializers-rails]: https://github.com/IvyApp/ivy-serializers-rails
|
data/ivy-serializers.gemspec
CHANGED
@@ -14,11 +14,12 @@ Gem::Specification.new do |spec|
|
|
14
14
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
15
15
|
spec.require_paths = ['lib']
|
16
16
|
|
17
|
-
spec.add_dependency 'activesupport', '>= 2.2.1'
|
18
17
|
spec.add_dependency 'hash_generator', '~> 1.1'
|
18
|
+
spec.add_dependency 'inflecto', '~> 0.0.2'
|
19
19
|
|
20
20
|
spec.add_development_dependency 'bundler', '~> 1.6'
|
21
|
+
spec.add_development_dependency 'json-schema-rspec', '~> 0.0.4'
|
21
22
|
spec.add_development_dependency 'rake'
|
22
|
-
spec.add_development_dependency 'rspec', '~> 3.
|
23
|
-
spec.add_development_dependency 'simplecov', '~> 0.
|
23
|
+
spec.add_development_dependency 'rspec', '~> 3.5'
|
24
|
+
spec.add_development_dependency 'simplecov', '~> 0.12.0'
|
24
25
|
end
|
@@ -28,7 +28,7 @@ module Ivy
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def generate_included_resources(generator)
|
31
|
-
|
31
|
+
generator.included_resources(@included_resources)
|
32
32
|
end
|
33
33
|
|
34
34
|
def generate_relationships(generator, resource)
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require '
|
1
|
+
require 'inflecto'
|
2
2
|
require 'ivy/serializers/formats/json'
|
3
3
|
|
4
4
|
module Ivy
|
@@ -41,7 +41,7 @@ module Ivy
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def singularize(name)
|
44
|
-
|
44
|
+
Inflecto.singularize(name.to_s)
|
45
45
|
end
|
46
46
|
end
|
47
47
|
end
|
@@ -1,5 +1,5 @@
|
|
1
|
-
require 'active_support/inflector'
|
2
1
|
require 'hash_generator'
|
2
|
+
require 'inflecto'
|
3
3
|
|
4
4
|
module Ivy
|
5
5
|
module Serializers
|
@@ -48,9 +48,11 @@ module Ivy
|
|
48
48
|
document.generate_included_resources(self)
|
49
49
|
end
|
50
50
|
|
51
|
-
def included_resources(
|
52
|
-
|
53
|
-
|
51
|
+
def included_resources(included_resources)
|
52
|
+
included_resources.each_pair do |resource_class, resources|
|
53
|
+
key = key_for_collection(resource_class).to_sym
|
54
|
+
@hash_gen.store_array(key) { resources(resources) }
|
55
|
+
end
|
54
56
|
end
|
55
57
|
|
56
58
|
def primary_resource(primary_resource_name, primary_resource)
|
@@ -85,15 +87,15 @@ module Ivy
|
|
85
87
|
end
|
86
88
|
|
87
89
|
def extract_type(resource)
|
88
|
-
|
90
|
+
Inflecto.dasherize(key_for_individual(resource.class))
|
89
91
|
end
|
90
92
|
|
91
93
|
def key_for_collection(resource_class)
|
92
|
-
|
94
|
+
Inflecto.pluralize(key_for_individual(resource_class))
|
93
95
|
end
|
94
96
|
|
95
97
|
def key_for_individual(resource_class)
|
96
|
-
|
98
|
+
Inflecto.underscore(resource_class.name)
|
97
99
|
end
|
98
100
|
end
|
99
101
|
end
|
@@ -21,7 +21,11 @@ module Ivy
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def included(document)
|
24
|
-
@hash_gen.
|
24
|
+
@hash_gen.store_array(:included) { super }
|
25
|
+
end
|
26
|
+
|
27
|
+
def included_resources(included_resources)
|
28
|
+
included_resources.each_value { |resources| resources(resources) }
|
25
29
|
end
|
26
30
|
|
27
31
|
def primary_resource(primary_resource_name, primary_resource)
|
@@ -5,13 +5,13 @@ module Ivy
|
|
5
5
|
module Serializers
|
6
6
|
class Mapping
|
7
7
|
def initialize(klass)
|
8
|
-
@
|
8
|
+
@attributes = {}
|
9
9
|
@relationships = {}
|
10
10
|
@klass = klass
|
11
11
|
end
|
12
12
|
|
13
13
|
def attribute(name, &block)
|
14
|
-
@
|
14
|
+
@attributes[name] = Attribute.new(name, &block)
|
15
15
|
end
|
16
16
|
|
17
17
|
def attributes(*names)
|
@@ -23,7 +23,7 @@ module Ivy
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def generate_attributes(generator, resource)
|
26
|
-
@
|
26
|
+
@attributes.each_value { |attribute| attribute.generate(generator, resource) }
|
27
27
|
end
|
28
28
|
|
29
29
|
def has_many(name, options={}, &block)
|
@@ -35,7 +35,7 @@ module Ivy
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def resource(generator, resource)
|
38
|
-
generator.attributes(resource) unless @
|
38
|
+
generator.attributes(resource) unless @attributes.empty?
|
39
39
|
generator.relationships(resource) unless @relationships.empty?
|
40
40
|
end
|
41
41
|
end
|
@@ -16,6 +16,8 @@ RSpec.describe Ivy::Serializers::Formats::JSONAPI do
|
|
16
16
|
context 'for an individual resource' do
|
17
17
|
let(:resource) { post }
|
18
18
|
|
19
|
+
it { should match_json_schema(:json_api) }
|
20
|
+
|
19
21
|
it { should eq({
|
20
22
|
:data => {
|
21
23
|
:type => 'post',
|
@@ -27,6 +29,8 @@ RSpec.describe Ivy::Serializers::Formats::JSONAPI do
|
|
27
29
|
context 'for a resource collection' do
|
28
30
|
let(:resource) { [post] }
|
29
31
|
|
32
|
+
it { should match_json_schema(:json_api) }
|
33
|
+
|
30
34
|
it { should eq({
|
31
35
|
:data => [{
|
32
36
|
:type => 'post',
|
@@ -50,6 +54,8 @@ RSpec.describe Ivy::Serializers::Formats::JSONAPI do
|
|
50
54
|
context 'for an individual resource' do
|
51
55
|
let(:resource) { post }
|
52
56
|
|
57
|
+
it { should match_json_schema(:json_api) }
|
58
|
+
|
53
59
|
it { should eq({
|
54
60
|
:data => {
|
55
61
|
:type => 'post',
|
@@ -64,6 +70,8 @@ RSpec.describe Ivy::Serializers::Formats::JSONAPI do
|
|
64
70
|
context 'for a resource collection' do
|
65
71
|
let(:resource) { [post] }
|
66
72
|
|
73
|
+
it { should match_json_schema(:json_api) }
|
74
|
+
|
67
75
|
it { should eq({
|
68
76
|
:data => [{
|
69
77
|
:type => 'post',
|
@@ -86,6 +94,8 @@ RSpec.describe Ivy::Serializers::Formats::JSONAPI do
|
|
86
94
|
context 'for an individual resource' do
|
87
95
|
let(:resource) { post }
|
88
96
|
|
97
|
+
it { should match_json_schema(:json_api) }
|
98
|
+
|
89
99
|
it { should eq({
|
90
100
|
:data => {
|
91
101
|
:type => 'post',
|
@@ -100,6 +110,8 @@ RSpec.describe Ivy::Serializers::Formats::JSONAPI do
|
|
100
110
|
context 'for a resource collection' do
|
101
111
|
let(:resource) { [post] }
|
102
112
|
|
113
|
+
it { should match_json_schema(:json_api) }
|
114
|
+
|
103
115
|
it { should eq({
|
104
116
|
:data => [{
|
105
117
|
:type => 'post',
|
@@ -129,6 +141,8 @@ RSpec.describe Ivy::Serializers::Formats::JSONAPI do
|
|
129
141
|
context 'for an individual resource' do
|
130
142
|
let(:resource) { post }
|
131
143
|
|
144
|
+
it { should match_json_schema(:json_api) }
|
145
|
+
|
132
146
|
it { should eq({
|
133
147
|
:data => {
|
134
148
|
:type => 'post',
|
@@ -144,6 +158,8 @@ RSpec.describe Ivy::Serializers::Formats::JSONAPI do
|
|
144
158
|
context 'with no related resource' do
|
145
159
|
let(:author) { nil }
|
146
160
|
|
161
|
+
it { should match_json_schema(:json_api) }
|
162
|
+
|
147
163
|
it { should eq({
|
148
164
|
:data => {
|
149
165
|
:type => 'post',
|
@@ -159,6 +175,8 @@ RSpec.describe Ivy::Serializers::Formats::JSONAPI do
|
|
159
175
|
context 'for a resource collection' do
|
160
176
|
let(:resource) { [post] }
|
161
177
|
|
178
|
+
it { should match_json_schema(:json_api) }
|
179
|
+
|
162
180
|
it { should eq({
|
163
181
|
:data => [{
|
164
182
|
:type => 'post',
|
@@ -183,6 +201,8 @@ RSpec.describe Ivy::Serializers::Formats::JSONAPI do
|
|
183
201
|
context 'for an individual resource' do
|
184
202
|
let(:resource) { post }
|
185
203
|
|
204
|
+
it { should match_json_schema(:json_api) }
|
205
|
+
|
186
206
|
it { should eq({
|
187
207
|
:data => {
|
188
208
|
:type => 'post',
|
@@ -198,6 +218,8 @@ RSpec.describe Ivy::Serializers::Formats::JSONAPI do
|
|
198
218
|
context 'with no related resource' do
|
199
219
|
let(:author) { nil }
|
200
220
|
|
221
|
+
it { should match_json_schema(:json_api) }
|
222
|
+
|
201
223
|
it { should eq({
|
202
224
|
:data => {
|
203
225
|
:type => 'post',
|
@@ -213,6 +235,8 @@ RSpec.describe Ivy::Serializers::Formats::JSONAPI do
|
|
213
235
|
context 'for a resource collection' do
|
214
236
|
let(:resource) { [post] }
|
215
237
|
|
238
|
+
it { should match_json_schema(:json_api) }
|
239
|
+
|
216
240
|
it { should eq({
|
217
241
|
:data => [{
|
218
242
|
:type => 'post',
|
@@ -237,6 +261,8 @@ RSpec.describe Ivy::Serializers::Formats::JSONAPI do
|
|
237
261
|
context 'for an individual resource' do
|
238
262
|
let(:resource) { post }
|
239
263
|
|
264
|
+
it { should match_json_schema(:json_api) }
|
265
|
+
|
240
266
|
it { should eq({
|
241
267
|
:data => {
|
242
268
|
:type => 'post',
|
@@ -248,17 +274,17 @@ RSpec.describe Ivy::Serializers::Formats::JSONAPI do
|
|
248
274
|
}
|
249
275
|
},
|
250
276
|
|
251
|
-
:included => {
|
252
|
-
:
|
253
|
-
|
254
|
-
|
255
|
-
}]
|
256
|
-
}
|
277
|
+
:included => [{
|
278
|
+
:id => '1',
|
279
|
+
:type => 'author'
|
280
|
+
}]
|
257
281
|
}) }
|
258
282
|
|
259
283
|
context 'with no related resource' do
|
260
284
|
let(:author) { nil }
|
261
285
|
|
286
|
+
it { should match_json_schema(:json_api) }
|
287
|
+
|
262
288
|
it { should eq({
|
263
289
|
:data => {
|
264
290
|
:type => 'post',
|
@@ -274,6 +300,8 @@ RSpec.describe Ivy::Serializers::Formats::JSONAPI do
|
|
274
300
|
context 'for a resource collection' do
|
275
301
|
let(:resource) { [post] }
|
276
302
|
|
303
|
+
it { should match_json_schema(:json_api) }
|
304
|
+
|
277
305
|
it { should eq({
|
278
306
|
:data => [{
|
279
307
|
:type => 'post',
|
@@ -285,12 +313,10 @@ RSpec.describe Ivy::Serializers::Formats::JSONAPI do
|
|
285
313
|
}
|
286
314
|
}],
|
287
315
|
|
288
|
-
:included => {
|
289
|
-
:
|
290
|
-
|
291
|
-
|
292
|
-
}]
|
293
|
-
}
|
316
|
+
:included => [{
|
317
|
+
:id => '1',
|
318
|
+
:type => 'author'
|
319
|
+
}]
|
294
320
|
}) }
|
295
321
|
end
|
296
322
|
end
|
@@ -305,6 +331,8 @@ RSpec.describe Ivy::Serializers::Formats::JSONAPI do
|
|
305
331
|
context 'for an individual resource' do
|
306
332
|
let(:resource) { post }
|
307
333
|
|
334
|
+
it { should match_json_schema(:json_api) }
|
335
|
+
|
308
336
|
it { should eq({
|
309
337
|
:data => {
|
310
338
|
:type => 'post',
|
@@ -320,6 +348,8 @@ RSpec.describe Ivy::Serializers::Formats::JSONAPI do
|
|
320
348
|
context 'with no related resource' do
|
321
349
|
let(:author) { nil }
|
322
350
|
|
351
|
+
it { should match_json_schema(:json_api) }
|
352
|
+
|
323
353
|
it { should eq({
|
324
354
|
:data => {
|
325
355
|
:type => 'post',
|
@@ -335,6 +365,8 @@ RSpec.describe Ivy::Serializers::Formats::JSONAPI do
|
|
335
365
|
context 'for a resource collection' do
|
336
366
|
let(:resource) { [post] }
|
337
367
|
|
368
|
+
it { should match_json_schema(:json_api) }
|
369
|
+
|
338
370
|
it { should eq({
|
339
371
|
:data => [{
|
340
372
|
:type => 'post',
|
@@ -366,6 +398,8 @@ RSpec.describe Ivy::Serializers::Formats::JSONAPI do
|
|
366
398
|
context 'for an individual resource' do
|
367
399
|
let(:resource) { post }
|
368
400
|
|
401
|
+
it { should match_json_schema(:json_api) }
|
402
|
+
|
369
403
|
it { should eq({
|
370
404
|
:data => {
|
371
405
|
:type => 'post',
|
@@ -382,6 +416,8 @@ RSpec.describe Ivy::Serializers::Formats::JSONAPI do
|
|
382
416
|
context 'for a resource collection' do
|
383
417
|
let(:resource) { [post] }
|
384
418
|
|
419
|
+
it { should match_json_schema(:json_api) }
|
420
|
+
|
385
421
|
it { should eq({
|
386
422
|
:data => [{
|
387
423
|
:type => 'post',
|
@@ -406,6 +442,8 @@ RSpec.describe Ivy::Serializers::Formats::JSONAPI do
|
|
406
442
|
context 'for an individual resource' do
|
407
443
|
let(:resource) { post }
|
408
444
|
|
445
|
+
it { should match_json_schema(:json_api) }
|
446
|
+
|
409
447
|
it { should eq({
|
410
448
|
:data => {
|
411
449
|
:type => 'post',
|
@@ -422,6 +460,8 @@ RSpec.describe Ivy::Serializers::Formats::JSONAPI do
|
|
422
460
|
context 'for a resource collection' do
|
423
461
|
let(:resource) { [post] }
|
424
462
|
|
463
|
+
it { should match_json_schema(:json_api) }
|
464
|
+
|
425
465
|
it { should eq({
|
426
466
|
:data => [{
|
427
467
|
:type => 'post',
|
@@ -446,6 +486,8 @@ RSpec.describe Ivy::Serializers::Formats::JSONAPI do
|
|
446
486
|
context 'for an individual resource' do
|
447
487
|
let(:resource) { post }
|
448
488
|
|
489
|
+
it { should match_json_schema(:json_api) }
|
490
|
+
|
449
491
|
it { should eq({
|
450
492
|
:data => {
|
451
493
|
:type => 'post',
|
@@ -457,18 +499,18 @@ RSpec.describe Ivy::Serializers::Formats::JSONAPI do
|
|
457
499
|
}
|
458
500
|
},
|
459
501
|
|
460
|
-
:included => {
|
461
|
-
:
|
462
|
-
|
463
|
-
|
464
|
-
}]
|
465
|
-
}
|
502
|
+
:included => [{
|
503
|
+
:type => 'comment',
|
504
|
+
:id => '1'
|
505
|
+
}]
|
466
506
|
}) }
|
467
507
|
end
|
468
508
|
|
469
509
|
context 'for a resource collection' do
|
470
510
|
let(:resource) { [post] }
|
471
511
|
|
512
|
+
it { should match_json_schema(:json_api) }
|
513
|
+
|
472
514
|
it { should eq({
|
473
515
|
:data => [{
|
474
516
|
:type => 'post',
|
@@ -480,12 +522,10 @@ RSpec.describe Ivy::Serializers::Formats::JSONAPI do
|
|
480
522
|
}
|
481
523
|
}],
|
482
524
|
|
483
|
-
:included => {
|
484
|
-
:
|
485
|
-
|
486
|
-
|
487
|
-
}]
|
488
|
-
}
|
525
|
+
:included => [{
|
526
|
+
:type => 'comment',
|
527
|
+
:id => '1'
|
528
|
+
}]
|
489
529
|
}) }
|
490
530
|
end
|
491
531
|
end
|
@@ -500,6 +540,8 @@ RSpec.describe Ivy::Serializers::Formats::JSONAPI do
|
|
500
540
|
context 'for an individual resource' do
|
501
541
|
let(:resource) { post }
|
502
542
|
|
543
|
+
it { should match_json_schema(:json_api) }
|
544
|
+
|
503
545
|
it { should eq({
|
504
546
|
:data => {
|
505
547
|
:type => 'post',
|
@@ -516,6 +558,8 @@ RSpec.describe Ivy::Serializers::Formats::JSONAPI do
|
|
516
558
|
context 'for a resource collection' do
|
517
559
|
let(:resource) { [post] }
|
518
560
|
|
561
|
+
it { should match_json_schema(:json_api) }
|
562
|
+
|
519
563
|
it { should eq({
|
520
564
|
:data => [{
|
521
565
|
:type => 'post',
|
@@ -0,0 +1,375 @@
|
|
1
|
+
{
|
2
|
+
"$schema": "http://json-schema.org/draft-04/schema#",
|
3
|
+
"title": "JSON API Schema",
|
4
|
+
"description": "This is a schema for responses in the JSON API format. For more, see http://jsonapi.org",
|
5
|
+
"oneOf": [
|
6
|
+
{
|
7
|
+
"$ref": "#/definitions/success"
|
8
|
+
},
|
9
|
+
{
|
10
|
+
"$ref": "#/definitions/failure"
|
11
|
+
},
|
12
|
+
{
|
13
|
+
"$ref": "#/definitions/info"
|
14
|
+
}
|
15
|
+
],
|
16
|
+
|
17
|
+
"definitions": {
|
18
|
+
"success": {
|
19
|
+
"type": "object",
|
20
|
+
"required": [
|
21
|
+
"data"
|
22
|
+
],
|
23
|
+
"properties": {
|
24
|
+
"data": {
|
25
|
+
"$ref": "#/definitions/data"
|
26
|
+
},
|
27
|
+
"included": {
|
28
|
+
"description": "To reduce the number of HTTP requests, servers **MAY** allow responses that include related resources along with the requested primary resources. Such responses are called \"compound documents\".",
|
29
|
+
"type": "array",
|
30
|
+
"items": {
|
31
|
+
"$ref": "#/definitions/resource"
|
32
|
+
},
|
33
|
+
"uniqueItems": true
|
34
|
+
},
|
35
|
+
"meta": {
|
36
|
+
"$ref": "#/definitions/meta"
|
37
|
+
},
|
38
|
+
"links": {
|
39
|
+
"description": "Link members related to the primary data.",
|
40
|
+
"allOf": [
|
41
|
+
{
|
42
|
+
"$ref": "#/definitions/links"
|
43
|
+
},
|
44
|
+
{
|
45
|
+
"$ref": "#/definitions/pagination"
|
46
|
+
}
|
47
|
+
]
|
48
|
+
},
|
49
|
+
"jsonapi": {
|
50
|
+
"$ref": "#/definitions/jsonapi"
|
51
|
+
}
|
52
|
+
},
|
53
|
+
"additionalProperties": false
|
54
|
+
},
|
55
|
+
"failure": {
|
56
|
+
"type": "object",
|
57
|
+
"required": [
|
58
|
+
"errors"
|
59
|
+
],
|
60
|
+
"properties": {
|
61
|
+
"errors": {
|
62
|
+
"type": "array",
|
63
|
+
"items": {
|
64
|
+
"$ref": "#/definitions/error"
|
65
|
+
},
|
66
|
+
"uniqueItems": true
|
67
|
+
},
|
68
|
+
"meta": {
|
69
|
+
"$ref": "#/definitions/meta"
|
70
|
+
},
|
71
|
+
"jsonapi": {
|
72
|
+
"$ref": "#/definitions/jsonapi"
|
73
|
+
}
|
74
|
+
},
|
75
|
+
"additionalProperties": false
|
76
|
+
},
|
77
|
+
"info": {
|
78
|
+
"type": "object",
|
79
|
+
"required": [
|
80
|
+
"meta"
|
81
|
+
],
|
82
|
+
"properties": {
|
83
|
+
"meta": {
|
84
|
+
"$ref": "#/definitions/meta"
|
85
|
+
},
|
86
|
+
"links": {
|
87
|
+
"$ref": "#/definitions/links"
|
88
|
+
},
|
89
|
+
"jsonapi": {
|
90
|
+
"$ref": "#/definitions/jsonapi"
|
91
|
+
}
|
92
|
+
},
|
93
|
+
"additionalProperties": false
|
94
|
+
},
|
95
|
+
|
96
|
+
"meta": {
|
97
|
+
"description": "Non-standard meta-information that can not be represented as an attribute or relationship.",
|
98
|
+
"type": "object",
|
99
|
+
"additionalProperties": true
|
100
|
+
},
|
101
|
+
"data": {
|
102
|
+
"description": "The document's \"primary data\" is a representation of the resource or collection of resources targeted by a request.",
|
103
|
+
"oneOf": [
|
104
|
+
{
|
105
|
+
"$ref": "#/definitions/resource"
|
106
|
+
},
|
107
|
+
{
|
108
|
+
"description": "An array of resource objects, an array of resource identifier objects, or an empty array ([]), for requests that target resource collections.",
|
109
|
+
"type": "array",
|
110
|
+
"items": {
|
111
|
+
"$ref": "#/definitions/resource"
|
112
|
+
},
|
113
|
+
"uniqueItems": true
|
114
|
+
},
|
115
|
+
{
|
116
|
+
"description": "null if the request is one that might correspond to a single resource, but doesn't currently.",
|
117
|
+
"type": "null"
|
118
|
+
}
|
119
|
+
]
|
120
|
+
},
|
121
|
+
"resource": {
|
122
|
+
"description": "\"Resource objects\" appear in a JSON API document to represent resources.",
|
123
|
+
"type": "object",
|
124
|
+
"required": [
|
125
|
+
"type",
|
126
|
+
"id"
|
127
|
+
],
|
128
|
+
"properties": {
|
129
|
+
"type": {
|
130
|
+
"type": "string"
|
131
|
+
},
|
132
|
+
"id": {
|
133
|
+
"type": "string"
|
134
|
+
},
|
135
|
+
"attributes": {
|
136
|
+
"$ref": "#/definitions/attributes"
|
137
|
+
},
|
138
|
+
"relationships": {
|
139
|
+
"$ref": "#/definitions/relationships"
|
140
|
+
},
|
141
|
+
"links": {
|
142
|
+
"$ref": "#/definitions/links"
|
143
|
+
},
|
144
|
+
"meta": {
|
145
|
+
"$ref": "#/definitions/meta"
|
146
|
+
}
|
147
|
+
},
|
148
|
+
"additionalProperties": false
|
149
|
+
},
|
150
|
+
|
151
|
+
"links": {
|
152
|
+
"description": "A resource object **MAY** contain references to other resource objects (\"relationships\"). Relationships may be to-one or to-many. Relationships can be specified by including a member in a resource's links object.",
|
153
|
+
"type": "object",
|
154
|
+
"properties": {
|
155
|
+
"self": {
|
156
|
+
"description": "A `self` member, whose value is a URL for the relationship itself (a \"relationship URL\"). This URL allows the client to directly manipulate the relationship. For example, it would allow a client to remove an `author` from an `article` without deleting the people resource itself.",
|
157
|
+
"type": "string",
|
158
|
+
"format": "uri"
|
159
|
+
},
|
160
|
+
"related": {
|
161
|
+
"$ref": "#/definitions/link"
|
162
|
+
}
|
163
|
+
},
|
164
|
+
"additionalProperties": true
|
165
|
+
},
|
166
|
+
"link": {
|
167
|
+
"description": "A link **MUST** be represented as either: a string containing the link's URL or a link object.",
|
168
|
+
"oneOf": [
|
169
|
+
{
|
170
|
+
"description": "A string containing the link's URL.",
|
171
|
+
"type": "string",
|
172
|
+
"format": "uri"
|
173
|
+
},
|
174
|
+
{
|
175
|
+
"type": "object",
|
176
|
+
"required": [
|
177
|
+
"href"
|
178
|
+
],
|
179
|
+
"properties": {
|
180
|
+
"href": {
|
181
|
+
"description": "A string containing the link's URL.",
|
182
|
+
"type": "string",
|
183
|
+
"format": "uri"
|
184
|
+
},
|
185
|
+
"meta": {
|
186
|
+
"$ref": "#/definitions/meta"
|
187
|
+
}
|
188
|
+
}
|
189
|
+
}
|
190
|
+
]
|
191
|
+
},
|
192
|
+
|
193
|
+
"attributes": {
|
194
|
+
"description": "Members of the attributes object (\"attributes\") represent information about the resource object in which it's defined.",
|
195
|
+
"type": "object",
|
196
|
+
"patternProperties": {
|
197
|
+
"^(?!relationships$|links$)\\w[-\\w]*$": {
|
198
|
+
"description": "Attributes may contain any valid JSON value."
|
199
|
+
}
|
200
|
+
},
|
201
|
+
"additionalProperties": false
|
202
|
+
},
|
203
|
+
|
204
|
+
"relationships": {
|
205
|
+
"description": "Members of the relationships object (\"relationships\") represent references from the resource object in which it's defined to other resource objects.",
|
206
|
+
"type": "object",
|
207
|
+
"patternProperties": {
|
208
|
+
"^\\w[-\\w]*$": {
|
209
|
+
"properties": {
|
210
|
+
"links": {
|
211
|
+
"$ref": "#/definitions/links"
|
212
|
+
},
|
213
|
+
"data": {
|
214
|
+
"description": "Member, whose value represents \"resource linkage\".",
|
215
|
+
"oneOf": [
|
216
|
+
{
|
217
|
+
"$ref": "#/definitions/relationshipToOne"
|
218
|
+
},
|
219
|
+
{
|
220
|
+
"$ref": "#/definitions/relationshipToMany"
|
221
|
+
}
|
222
|
+
]
|
223
|
+
},
|
224
|
+
"meta": {
|
225
|
+
"$ref": "#/definitions/meta"
|
226
|
+
}
|
227
|
+
},
|
228
|
+
"anyOf": [
|
229
|
+
{"required": ["data"]},
|
230
|
+
{"required": ["meta"]},
|
231
|
+
{"required": ["links"]}
|
232
|
+
],
|
233
|
+
"additionalProperties": false
|
234
|
+
}
|
235
|
+
},
|
236
|
+
"additionalProperties": false
|
237
|
+
},
|
238
|
+
"relationshipToOne": {
|
239
|
+
"description": "References to other resource objects in a to-one (\"relationship\"). Relationships can be specified by including a member in a resource's links object.",
|
240
|
+
"anyOf": [
|
241
|
+
{
|
242
|
+
"$ref": "#/definitions/empty"
|
243
|
+
},
|
244
|
+
{
|
245
|
+
"$ref": "#/definitions/linkage"
|
246
|
+
}
|
247
|
+
]
|
248
|
+
},
|
249
|
+
"relationshipToMany": {
|
250
|
+
"description": "An array of objects each containing \"type\" and \"id\" members for to-many relationships.",
|
251
|
+
"type": "array",
|
252
|
+
"items": {
|
253
|
+
"$ref": "#/definitions/linkage"
|
254
|
+
},
|
255
|
+
"uniqueItems": true
|
256
|
+
},
|
257
|
+
"empty": {
|
258
|
+
"description": "Describes an empty to-one relationship.",
|
259
|
+
"type": "null"
|
260
|
+
},
|
261
|
+
"linkage": {
|
262
|
+
"description": "The \"type\" and \"id\" to non-empty members.",
|
263
|
+
"type": "object",
|
264
|
+
"required": [
|
265
|
+
"type",
|
266
|
+
"id"
|
267
|
+
],
|
268
|
+
"properties": {
|
269
|
+
"type": {
|
270
|
+
"type": "string"
|
271
|
+
},
|
272
|
+
"id": {
|
273
|
+
"type": "string"
|
274
|
+
},
|
275
|
+
"meta": {
|
276
|
+
"$ref": "#/definitions/meta"
|
277
|
+
}
|
278
|
+
},
|
279
|
+
"additionalProperties": false
|
280
|
+
},
|
281
|
+
"pagination": {
|
282
|
+
"type": "object",
|
283
|
+
"properties": {
|
284
|
+
"first": {
|
285
|
+
"description": "The first page of data",
|
286
|
+
"oneOf": [
|
287
|
+
{ "type": "string", "format": "uri" },
|
288
|
+
{ "type": "null" }
|
289
|
+
]
|
290
|
+
},
|
291
|
+
"last": {
|
292
|
+
"description": "The last page of data",
|
293
|
+
"oneOf": [
|
294
|
+
{ "type": "string", "format": "uri" },
|
295
|
+
{ "type": "null" }
|
296
|
+
]
|
297
|
+
},
|
298
|
+
"prev": {
|
299
|
+
"description": "The previous page of data",
|
300
|
+
"oneOf": [
|
301
|
+
{ "type": "string", "format": "uri" },
|
302
|
+
{ "type": "null" }
|
303
|
+
]
|
304
|
+
},
|
305
|
+
"next": {
|
306
|
+
"description": "The next page of data",
|
307
|
+
"oneOf": [
|
308
|
+
{ "type": "string", "format": "uri" },
|
309
|
+
{ "type": "null" }
|
310
|
+
]
|
311
|
+
}
|
312
|
+
}
|
313
|
+
},
|
314
|
+
|
315
|
+
"jsonapi": {
|
316
|
+
"description": "An object describing the server's implementation",
|
317
|
+
"type": "object",
|
318
|
+
"properties": {
|
319
|
+
"version": {
|
320
|
+
"type": "string"
|
321
|
+
},
|
322
|
+
"meta": {
|
323
|
+
"$ref": "#/definitions/meta"
|
324
|
+
}
|
325
|
+
},
|
326
|
+
"additionalProperties": false
|
327
|
+
},
|
328
|
+
|
329
|
+
"error": {
|
330
|
+
"type": "object",
|
331
|
+
"properties": {
|
332
|
+
"id": {
|
333
|
+
"description": "A unique identifier for this particular occurrence of the problem.",
|
334
|
+
"type": "string"
|
335
|
+
},
|
336
|
+
"links": {
|
337
|
+
"$ref": "#/definitions/links"
|
338
|
+
},
|
339
|
+
"status": {
|
340
|
+
"description": "The HTTP status code applicable to this problem, expressed as a string value.",
|
341
|
+
"type": "string"
|
342
|
+
},
|
343
|
+
"code": {
|
344
|
+
"description": "An application-specific error code, expressed as a string value.",
|
345
|
+
"type": "string"
|
346
|
+
},
|
347
|
+
"title": {
|
348
|
+
"description": "A short, human-readable summary of the problem. It **SHOULD NOT** change from occurrence to occurrence of the problem, except for purposes of localization.",
|
349
|
+
"type": "string"
|
350
|
+
},
|
351
|
+
"detail": {
|
352
|
+
"description": "A human-readable explanation specific to this occurrence of the problem.",
|
353
|
+
"type": "string"
|
354
|
+
},
|
355
|
+
"source": {
|
356
|
+
"type": "object",
|
357
|
+
"properties": {
|
358
|
+
"pointer": {
|
359
|
+
"description": "A JSON Pointer [RFC6901] to the associated entity in the request document [e.g. \"/data\" for a primary data object, or \"/data/attributes/title\" for a specific attribute].",
|
360
|
+
"type": "string"
|
361
|
+
},
|
362
|
+
"parameter": {
|
363
|
+
"description": "A string indicating which query parameter caused the error.",
|
364
|
+
"type": "string"
|
365
|
+
}
|
366
|
+
}
|
367
|
+
},
|
368
|
+
"meta": {
|
369
|
+
"$ref": "#/definitions/meta"
|
370
|
+
}
|
371
|
+
},
|
372
|
+
"additionalProperties": false
|
373
|
+
}
|
374
|
+
}
|
375
|
+
}
|
data/spec/spec_helper.rb
CHANGED
@@ -2,6 +2,8 @@ require 'simplecov'
|
|
2
2
|
|
3
3
|
SimpleCov.start
|
4
4
|
|
5
|
+
require 'json-schema-rspec'
|
6
|
+
|
5
7
|
# This file was generated by the `rspec --init` command. Conventionally, all
|
6
8
|
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
7
9
|
# The generated `.rspec` file contains `--require spec_helper` which will cause
|
@@ -21,6 +23,13 @@ SimpleCov.start
|
|
21
23
|
#
|
22
24
|
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
23
25
|
RSpec.configure do |config|
|
26
|
+
config.include JSON::SchemaMatchers
|
27
|
+
|
28
|
+
# Load schema files into config.json_schemas.
|
29
|
+
Dir[File.join(File.expand_path('../schemas', __FILE__), '**', '*.json')].each do |file|
|
30
|
+
config.json_schemas[File.basename(file, '.json').to_sym] = file
|
31
|
+
end
|
32
|
+
|
24
33
|
# rspec-expectations config goes here. You can use an alternate
|
25
34
|
# assertion/expectation library such as wrong or the stdlib/minitest
|
26
35
|
# assertions if you prefer.
|
metadata
CHANGED
@@ -1,43 +1,43 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ivy-serializers
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dray Lacy
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-11-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: hash_generator
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: '1.1'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: '1.1'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: inflecto
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: 0.0.2
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: 0.0.2
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: bundler
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -52,6 +52,20 @@ dependencies:
|
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '1.6'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: json-schema-rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.0.4
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.0.4
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: rake
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -72,28 +86,28 @@ dependencies:
|
|
72
86
|
requirements:
|
73
87
|
- - "~>"
|
74
88
|
- !ruby/object:Gem::Version
|
75
|
-
version: 3.
|
89
|
+
version: '3.5'
|
76
90
|
type: :development
|
77
91
|
prerelease: false
|
78
92
|
version_requirements: !ruby/object:Gem::Requirement
|
79
93
|
requirements:
|
80
94
|
- - "~>"
|
81
95
|
- !ruby/object:Gem::Version
|
82
|
-
version: 3.
|
96
|
+
version: '3.5'
|
83
97
|
- !ruby/object:Gem::Dependency
|
84
98
|
name: simplecov
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|
86
100
|
requirements:
|
87
101
|
- - "~>"
|
88
102
|
- !ruby/object:Gem::Version
|
89
|
-
version: 0.
|
103
|
+
version: 0.12.0
|
90
104
|
type: :development
|
91
105
|
prerelease: false
|
92
106
|
version_requirements: !ruby/object:Gem::Requirement
|
93
107
|
requirements:
|
94
108
|
- - "~>"
|
95
109
|
- !ruby/object:Gem::Version
|
96
|
-
version: 0.
|
110
|
+
version: 0.12.0
|
97
111
|
description:
|
98
112
|
email:
|
99
113
|
- dray@envylabs.com
|
@@ -104,6 +118,7 @@ files:
|
|
104
118
|
- ".gitignore"
|
105
119
|
- ".rspec"
|
106
120
|
- ".travis.yml"
|
121
|
+
- CHANGELOG.md
|
107
122
|
- Gemfile
|
108
123
|
- LICENSE.txt
|
109
124
|
- README.md
|
@@ -132,6 +147,7 @@ files:
|
|
132
147
|
- spec/integration/formats/json_api_spec.rb
|
133
148
|
- spec/integration/formats/json_spec.rb
|
134
149
|
- spec/integration/serializer_spec.rb
|
150
|
+
- spec/schemas/json_api.json
|
135
151
|
- spec/spec_helper.rb
|
136
152
|
homepage: ''
|
137
153
|
licenses:
|
@@ -153,7 +169,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
153
169
|
version: '0'
|
154
170
|
requirements: []
|
155
171
|
rubyforge_project:
|
156
|
-
rubygems_version: 2.4.
|
172
|
+
rubygems_version: 2.4.5.1
|
157
173
|
signing_key:
|
158
174
|
specification_version: 4
|
159
175
|
summary: JSON serialization for client-side apps.
|
@@ -162,4 +178,5 @@ test_files:
|
|
162
178
|
- spec/integration/formats/json_api_spec.rb
|
163
179
|
- spec/integration/formats/json_spec.rb
|
164
180
|
- spec/integration/serializer_spec.rb
|
181
|
+
- spec/schemas/json_api.json
|
165
182
|
- spec/spec_helper.rb
|