jsonapi-serializers 1.0.1 → 2.0.0.pre.beta.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +2 -4
- data/README.md +25 -0
- data/jsonapi-serializers.gemspec +1 -0
- data/lib/jsonapi-serializers/serializer.rb +117 -106
- data/lib/jsonapi-serializers/version.rb +1 -1
- data/spec/serializer_spec.rb +101 -0
- metadata +19 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f99b86af11e529f51cb077d231c973924183808e8d88b0660fa44a2112098a28
|
4
|
+
data.tar.gz: 80b21e2bd747fa2c838ce4ca73e62f1ecf6121b868fcb8edd045dc4bf31604b0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 88010cf85c872256685733787d5bb7a74a3dd4ff338797f2f5cd66b3fbc708b5293fbf63c1033d6a4adb56e430d5878be518f3ef98456bf13e3861a08eb6f8ac
|
7
|
+
data.tar.gz: fd1d79a679235e3115bce25d7b16054cc16097512a52a05df402d0a8ac754c0aad14136054bddbf2c84e99618be9e6058a220e0e64ddbe6e0eb99b6c0c8082b0
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -29,6 +29,7 @@ This library is up-to-date with the finalized v1 JSON API spec.
|
|
29
29
|
* [Compound documents and includes](#compound-documents-and-includes)
|
30
30
|
* [Relationship path handling](#relationship-path-handling)
|
31
31
|
* [Control links and data in relationships](#control-links-and-data-in-relationships)
|
32
|
+
* [Instrumentation](#instrumentation)
|
32
33
|
* [Rails example](#rails-example)
|
33
34
|
* [Sinatra example](#sinatra-example)
|
34
35
|
* [Unfinished business](#unfinished-business)
|
@@ -641,6 +642,30 @@ Notice that linkage data is now included for the `author` relationship:
|
|
641
642
|
}
|
642
643
|
```
|
643
644
|
|
645
|
+
## Instrumentation
|
646
|
+
|
647
|
+
Using [ActiveSupport::Notifications](https://api.rubyonrails.org/classes/ActiveSupport/Notifications.html) you can subscribe to key notifications to better understand the performance of your serialization.
|
648
|
+
|
649
|
+
The following notifications can be subscribed to:
|
650
|
+
|
651
|
+
* `render.jsonapi_serializers.serialize_primary` - time spent serializing a single object
|
652
|
+
* `render.jsonapi_serializers.find_recursive_relationships` - time spent finding objects to serialize through relationships
|
653
|
+
|
654
|
+
This is an example of how you might subscribe to all events that come from `jsonapi-serializers`.
|
655
|
+
|
656
|
+
```ruby
|
657
|
+
require 'active_support/notifications'
|
658
|
+
|
659
|
+
ActiveSupport::Notifications.subscribe(/^render\.jsonapi_serializers\..*/) do |*args|
|
660
|
+
event = ActiveSupport::Notifications::Event.new(*args)
|
661
|
+
|
662
|
+
puts event.name
|
663
|
+
puts event.time
|
664
|
+
puts event.end
|
665
|
+
puts event.payload
|
666
|
+
end
|
667
|
+
```
|
668
|
+
|
644
669
|
## Rails example
|
645
670
|
|
646
671
|
```ruby
|
data/jsonapi-serializers.gemspec
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'set'
|
2
2
|
require 'active_support/inflector'
|
3
|
+
require 'active_support/notifications'
|
3
4
|
|
4
5
|
module JSONAPI
|
5
6
|
module Serializer
|
@@ -394,38 +395,43 @@ module JSONAPI
|
|
394
395
|
end
|
395
396
|
|
396
397
|
def self.serialize_primary(object, options = {})
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
398
|
+
ActiveSupport::Notifications.instrument(
|
399
|
+
'render.jsonapi_serializers.serialize_primary',
|
400
|
+
{class_name: object&.class&.name}
|
401
|
+
) do
|
402
|
+
serializer_class = options[:serializer] || find_serializer_class(object, options)
|
403
|
+
|
404
|
+
# Spec: Primary data MUST be either:
|
405
|
+
# - a single resource object or null, for requests that target single resources.
|
406
|
+
# http://jsonapi.org/format/#document-structure-top-level
|
407
|
+
return if object.nil?
|
408
|
+
|
409
|
+
serializer = serializer_class.new(object, options)
|
410
|
+
data = {
|
411
|
+
'type' => serializer.type.to_s,
|
412
|
+
}
|
413
|
+
|
414
|
+
# "The id member is not required when the resource object originates at the client
|
415
|
+
# and represents a new resource to be created on the server."
|
416
|
+
# http://jsonapi.org/format/#document-resource-objects
|
417
|
+
# We'll assume that if the id is blank, it means the resource is to be created.
|
418
|
+
data['id'] = serializer.id.to_s if serializer.id && !serializer.id.empty?
|
419
|
+
|
420
|
+
# Merge in optional top-level members if they are non-nil.
|
421
|
+
# http://jsonapi.org/format/#document-structure-resource-objects
|
422
|
+
# Call the methods once now to avoid calling them twice when evaluating the if's below.
|
423
|
+
attributes = serializer.attributes
|
424
|
+
links = serializer.links
|
425
|
+
relationships = serializer.relationships
|
426
|
+
jsonapi = serializer.jsonapi
|
427
|
+
meta = serializer.meta
|
428
|
+
data['attributes'] = attributes if !attributes.empty?
|
429
|
+
data['links'] = links if !links.empty?
|
430
|
+
data['relationships'] = relationships if !relationships.empty?
|
431
|
+
data['jsonapi'] = jsonapi if !jsonapi.nil?
|
432
|
+
data['meta'] = meta if !meta.nil?
|
433
|
+
data
|
434
|
+
end
|
429
435
|
end
|
430
436
|
class << self; protected :serialize_primary; end
|
431
437
|
|
@@ -447,88 +453,93 @@ module JSONAPI
|
|
447
453
|
# ['users', '2'] => {object: <User>, include_linkages: []},
|
448
454
|
# }
|
449
455
|
def self.find_recursive_relationships(root_object, root_inclusion_tree, results, options)
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
456
|
+
ActiveSupport::Notifications.instrument(
|
457
|
+
'render.jsonapi_serializers.find_recursive_relationships',
|
458
|
+
{class_name: root_object.class.name},
|
459
|
+
) do
|
460
|
+
root_inclusion_tree.each do |attribute_name, child_inclusion_tree|
|
461
|
+
# Skip the sentinal value, but we need to preserve it for siblings.
|
462
|
+
next if attribute_name == :_include
|
463
|
+
|
464
|
+
serializer = JSONAPI::Serializer.find_serializer(root_object, options)
|
465
|
+
unformatted_attr_name = serializer.unformat_name(attribute_name).to_sym
|
466
|
+
|
467
|
+
# We know the name of this relationship, but we don't know where it is stored internally.
|
468
|
+
# Check if it is a has_one or has_many relationship.
|
469
|
+
object = nil
|
470
|
+
is_collection = false
|
471
|
+
is_valid_attr = false
|
472
|
+
if serializer.has_one_relationships.has_key?(unformatted_attr_name)
|
473
|
+
is_valid_attr = true
|
474
|
+
attr_data = serializer.has_one_relationships[unformatted_attr_name]
|
475
|
+
object = serializer.has_one_relationship(unformatted_attr_name, attr_data)
|
476
|
+
elsif serializer.has_many_relationships.has_key?(unformatted_attr_name)
|
477
|
+
is_valid_attr = true
|
478
|
+
is_collection = true
|
479
|
+
attr_data = serializer.has_many_relationships[unformatted_attr_name]
|
480
|
+
object = serializer.has_many_relationship(unformatted_attr_name, attr_data)
|
481
|
+
end
|
472
482
|
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
483
|
+
if !is_valid_attr
|
484
|
+
raise JSONAPI::Serializer::InvalidIncludeError.new(
|
485
|
+
"'#{attribute_name}' is not a valid include.")
|
486
|
+
end
|
477
487
|
|
478
|
-
|
479
|
-
|
488
|
+
if attribute_name != serializer.format_name(attribute_name)
|
489
|
+
expected_name = serializer.format_name(attribute_name)
|
480
490
|
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
491
|
+
raise JSONAPI::Serializer::InvalidIncludeError.new(
|
492
|
+
"'#{attribute_name}' is not a valid include. Did you mean '#{expected_name}' ?"
|
493
|
+
)
|
494
|
+
end
|
495
|
+
|
496
|
+
# We're finding relationships for compound documents, so skip anything that doesn't exist.
|
497
|
+
next if object.nil?
|
485
498
|
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
if child_inclusion_tree[inclusion_name][:_include]
|
515
|
-
current_child_includes << inclusion_name
|
499
|
+
# Full linkage: a request for comments.author MUST automatically include comments
|
500
|
+
# in the response.
|
501
|
+
objects = is_collection ? object : [object]
|
502
|
+
if child_inclusion_tree[:_include] == true
|
503
|
+
# Include the current level objects if the _include attribute exists.
|
504
|
+
# If it is not set, that indicates that this is an inner path and not a leaf and will
|
505
|
+
# be followed by the recursion below.
|
506
|
+
objects.each do |obj|
|
507
|
+
obj_serializer = JSONAPI::Serializer.find_serializer(obj, options)
|
508
|
+
# Use keys of ['posts', '1'] for the results to enforce uniqueness.
|
509
|
+
# Spec: A compound document MUST NOT include more than one resource object for each
|
510
|
+
# type and id pair.
|
511
|
+
# http://jsonapi.org/format/#document-structure-compound-documents
|
512
|
+
key = [obj_serializer.type, obj_serializer.id]
|
513
|
+
|
514
|
+
# This is special: we know at this level if a child of this parent will also been
|
515
|
+
# included in the compound document, so we can compute exactly what linkages should
|
516
|
+
# be included by the object at this level. This satisfies this part of the spec:
|
517
|
+
#
|
518
|
+
# Spec: Resource linkage in a compound document allows a client to link together
|
519
|
+
# all of the included resource objects without having to GET any relationship URLs.
|
520
|
+
# http://jsonapi.org/format/#document-structure-resource-relationships
|
521
|
+
current_child_includes = []
|
522
|
+
inclusion_names = child_inclusion_tree.keys.reject { |k| k == :_include }
|
523
|
+
inclusion_names.each do |inclusion_name|
|
524
|
+
if child_inclusion_tree[inclusion_name][:_include]
|
525
|
+
current_child_includes << inclusion_name
|
526
|
+
end
|
516
527
|
end
|
517
|
-
end
|
518
528
|
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
529
|
+
# Special merge: we might see this object multiple times in the course of recursion,
|
530
|
+
# so merge the include_linkages each time we see it to load all the relevant linkages.
|
531
|
+
current_child_includes += results[key] && results[key][:include_linkages] || []
|
532
|
+
current_child_includes.uniq!
|
533
|
+
results[key] = {object: obj, include_linkages: current_child_includes}
|
534
|
+
end
|
524
535
|
end
|
525
|
-
end
|
526
536
|
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
537
|
+
# Recurse deeper!
|
538
|
+
if !child_inclusion_tree.empty?
|
539
|
+
# For each object we just loaded, find all deeper recursive relationships.
|
540
|
+
objects.each do |obj|
|
541
|
+
find_recursive_relationships(obj, child_inclusion_tree, results, options)
|
542
|
+
end
|
532
543
|
end
|
533
544
|
end
|
534
545
|
end
|
data/spec/serializer_spec.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'active_model/errors'
|
2
2
|
require 'active_model/naming'
|
3
3
|
require 'active_model/translation'
|
4
|
+
require 'pry'
|
4
5
|
|
5
6
|
describe JSONAPI::Serializer do
|
6
7
|
def serialize_primary(object, options = {})
|
@@ -16,6 +17,7 @@ describe JSONAPI::Serializer do
|
|
16
17
|
primary_data = serialize_primary(nil, {serializer: MyApp::PostSerializer})
|
17
18
|
expect(primary_data).to be_nil
|
18
19
|
end
|
20
|
+
|
19
21
|
it 'can serialize primary data for a simple object' do
|
20
22
|
post = create(:post)
|
21
23
|
primary_data = serialize_primary(post, {serializer: MyApp::SimplestPostSerializer})
|
@@ -31,6 +33,7 @@ describe JSONAPI::Serializer do
|
|
31
33
|
},
|
32
34
|
})
|
33
35
|
end
|
36
|
+
|
34
37
|
it 'can serialize primary data for a simple object with a long name' do
|
35
38
|
long_comment = create(:long_comment, post: create(:post))
|
36
39
|
primary_data = serialize_primary(long_comment, {serializer: MyApp::LongCommentSerializer})
|
@@ -59,6 +62,7 @@ describe JSONAPI::Serializer do
|
|
59
62
|
},
|
60
63
|
})
|
61
64
|
end
|
65
|
+
|
62
66
|
it 'can serialize primary data for a simple object with resource-level metadata' do
|
63
67
|
post = create(:post)
|
64
68
|
primary_data = serialize_primary(post, {serializer: MyApp::PostSerializerWithMetadata})
|
@@ -80,6 +84,7 @@ describe JSONAPI::Serializer do
|
|
80
84
|
},
|
81
85
|
})
|
82
86
|
end
|
87
|
+
|
83
88
|
context 'without any linkage includes (default)' do
|
84
89
|
it 'can serialize primary data for an object with to-one and to-many relationships' do
|
85
90
|
post = create(:post)
|
@@ -111,6 +116,7 @@ describe JSONAPI::Serializer do
|
|
111
116
|
},
|
112
117
|
})
|
113
118
|
end
|
119
|
+
|
114
120
|
it 'does not include relationship links if relationship_{self_link,_related_link} are nil' do
|
115
121
|
post = create(:post)
|
116
122
|
primary_data = serialize_primary(post, {serializer: MyApp::PostSerializerWithoutLinks})
|
@@ -129,6 +135,7 @@ describe JSONAPI::Serializer do
|
|
129
135
|
},
|
130
136
|
})
|
131
137
|
end
|
138
|
+
|
132
139
|
it 'does not include id when it is nil' do
|
133
140
|
post = create(:post)
|
134
141
|
post.id = nil
|
@@ -145,6 +152,7 @@ describe JSONAPI::Serializer do
|
|
145
152
|
},
|
146
153
|
})
|
147
154
|
end
|
155
|
+
|
148
156
|
it 'serializes object when multiple attributes are declared once' do
|
149
157
|
post = create(:post)
|
150
158
|
primary_data = serialize_primary(post, {serializer: MyApp::MultipleAttributesSerializer})
|
@@ -161,6 +169,7 @@ describe JSONAPI::Serializer do
|
|
161
169
|
})
|
162
170
|
end
|
163
171
|
end
|
172
|
+
|
164
173
|
context 'with linkage includes' do
|
165
174
|
it 'can serialize primary data for a null to-one relationship' do
|
166
175
|
post = create(:post, author: nil)
|
@@ -200,6 +209,7 @@ describe JSONAPI::Serializer do
|
|
200
209
|
},
|
201
210
|
})
|
202
211
|
end
|
212
|
+
|
203
213
|
it 'can serialize primary data for a simple to-one relationship' do
|
204
214
|
post = create(:post, :with_author)
|
205
215
|
options = {
|
@@ -241,6 +251,7 @@ describe JSONAPI::Serializer do
|
|
241
251
|
},
|
242
252
|
})
|
243
253
|
end
|
254
|
+
|
244
255
|
it 'can serialize primary data for an empty to-many relationship' do
|
245
256
|
post = create(:post, long_comments: [])
|
246
257
|
options = {
|
@@ -279,6 +290,7 @@ describe JSONAPI::Serializer do
|
|
279
290
|
},
|
280
291
|
})
|
281
292
|
end
|
293
|
+
|
282
294
|
it 'can serialize primary data for a simple to-many relationship' do
|
283
295
|
long_comments = create_list(:long_comment, 2)
|
284
296
|
post = create(:post, long_comments: long_comments)
|
@@ -328,6 +340,7 @@ describe JSONAPI::Serializer do
|
|
328
340
|
})
|
329
341
|
end
|
330
342
|
end
|
343
|
+
|
331
344
|
it 'can serialize primary data for an empty serializer with no attributes' do
|
332
345
|
post = create(:post)
|
333
346
|
primary_data = serialize_primary(post, {serializer: MyApp::EmptySerializer})
|
@@ -339,6 +352,7 @@ describe JSONAPI::Serializer do
|
|
339
352
|
},
|
340
353
|
})
|
341
354
|
end
|
355
|
+
|
342
356
|
it 'can find the correct serializer by object class name' do
|
343
357
|
post = create(:post)
|
344
358
|
primary_data = serialize_primary(post)
|
@@ -502,22 +516,26 @@ describe JSONAPI::Serializer do
|
|
502
516
|
it 'can serialize a nil object' do
|
503
517
|
expect(JSONAPI::Serializer.serialize(nil)).to eq({'data' => nil})
|
504
518
|
end
|
519
|
+
|
505
520
|
it 'can serialize a nil object with includes' do
|
506
521
|
# Also, the include argument is not validated in this case because we don't know the type.
|
507
522
|
data = JSONAPI::Serializer.serialize(nil, include: ['fake'])
|
508
523
|
expect(data).to eq({'data' => nil, 'included' => []})
|
509
524
|
end
|
525
|
+
|
510
526
|
it 'can serialize an empty array' do
|
511
527
|
# Also, the include argument is not validated in this case because we don't know the type.
|
512
528
|
data = JSONAPI::Serializer.serialize([], is_collection: true, include: ['fake'])
|
513
529
|
expect(data).to eq({'data' => [], 'included' => []})
|
514
530
|
end
|
531
|
+
|
515
532
|
it 'can serialize a simple object' do
|
516
533
|
post = create(:post)
|
517
534
|
expect(JSONAPI::Serializer.serialize(post)).to eq({
|
518
535
|
'data' => serialize_primary(post, {serializer: MyApp::PostSerializer}),
|
519
536
|
})
|
520
537
|
end
|
538
|
+
|
521
539
|
it 'can include a top level jsonapi node' do
|
522
540
|
post = create(:post)
|
523
541
|
jsonapi_version = {'version' => '1.0'}
|
@@ -526,6 +544,7 @@ describe JSONAPI::Serializer do
|
|
526
544
|
'data' => serialize_primary(post, {serializer: MyApp::PostSerializer}),
|
527
545
|
})
|
528
546
|
end
|
547
|
+
|
529
548
|
it 'can include a top level meta node' do
|
530
549
|
post = create(:post)
|
531
550
|
meta = {authors: ['Yehuda Katz', 'Steve Klabnik'], copyright: 'Copyright 2015 Example Corp.'}
|
@@ -534,6 +553,7 @@ describe JSONAPI::Serializer do
|
|
534
553
|
'data' => serialize_primary(post, {serializer: MyApp::PostSerializer}),
|
535
554
|
})
|
536
555
|
end
|
556
|
+
|
537
557
|
it 'can include a top level links node' do
|
538
558
|
post = create(:post)
|
539
559
|
links = {self: 'http://example.com/posts'}
|
@@ -542,6 +562,7 @@ describe JSONAPI::Serializer do
|
|
542
562
|
'data' => serialize_primary(post, {serializer: MyApp::PostSerializer}),
|
543
563
|
})
|
544
564
|
end
|
565
|
+
|
545
566
|
# TODO: remove this code on next major release
|
546
567
|
it 'can include a top level errors node - deprecated' do
|
547
568
|
post = create(:post)
|
@@ -562,15 +583,18 @@ describe JSONAPI::Serializer do
|
|
562
583
|
'data' => serialize_primary(post, {serializer: MyApp::PostSerializer}),
|
563
584
|
})
|
564
585
|
end
|
586
|
+
|
565
587
|
it 'can serialize a single object with an `each` method by passing skip_collection_check: true' do
|
566
588
|
post = create(:post)
|
567
589
|
post.define_singleton_method(:each) do
|
568
590
|
"defining this just to defeat the duck-type check"
|
569
591
|
end
|
592
|
+
|
570
593
|
expect(JSONAPI::Serializer.serialize(post, skip_collection_check: true)).to eq({
|
571
594
|
'data' => serialize_primary(post, {serializer: MyApp::PostSerializer}),
|
572
595
|
})
|
573
596
|
end
|
597
|
+
|
574
598
|
it 'can serialize a collection' do
|
575
599
|
posts = create_list(:post, 2)
|
576
600
|
expect(JSONAPI::Serializer.serialize(posts, is_collection: true)).to eq({
|
@@ -580,6 +604,7 @@ describe JSONAPI::Serializer do
|
|
580
604
|
],
|
581
605
|
})
|
582
606
|
end
|
607
|
+
|
583
608
|
it 'raises AmbiguousCollectionError if is_collection is not passed' do
|
584
609
|
posts = create_list(:post, 2)
|
585
610
|
error = JSONAPI::Serializer::AmbiguousCollectionError
|
@@ -596,10 +621,12 @@ describe JSONAPI::Serializer do
|
|
596
621
|
options = {serializer: MyApp::PostSerializer}
|
597
622
|
expect(JSONAPI::Serializer.serialize(nil, options)).to eq({'data' => nil})
|
598
623
|
end
|
624
|
+
|
599
625
|
it 'can serialize an empty array when given serializer' do
|
600
626
|
options = {is_collection: true, serializer: MyApp::PostSerializer}
|
601
627
|
expect(JSONAPI::Serializer.serialize([], options)).to eq({'data' => []})
|
602
628
|
end
|
629
|
+
|
603
630
|
it 'can serialize a simple object when given serializer' do
|
604
631
|
post = create(:post)
|
605
632
|
options = {serializer: MyApp::SimplestPostSerializer}
|
@@ -607,6 +634,7 @@ describe JSONAPI::Serializer do
|
|
607
634
|
'data' => serialize_primary(post, {serializer: MyApp::SimplestPostSerializer}),
|
608
635
|
})
|
609
636
|
end
|
637
|
+
|
610
638
|
it 'handles include of nil to-one relationship with compound document' do
|
611
639
|
post = create(:post)
|
612
640
|
|
@@ -619,6 +647,7 @@ describe JSONAPI::Serializer do
|
|
619
647
|
'included' => [],
|
620
648
|
})
|
621
649
|
end
|
650
|
+
|
622
651
|
it 'handles include of simple to-one relationship with compound document' do
|
623
652
|
post = create(:post, :with_author)
|
624
653
|
|
@@ -633,6 +662,7 @@ describe JSONAPI::Serializer do
|
|
633
662
|
],
|
634
663
|
})
|
635
664
|
end
|
665
|
+
|
636
666
|
it 'handles include of empty to-many relationships with compound document' do
|
637
667
|
post = create(:post, :with_author, long_comments: [])
|
638
668
|
|
@@ -645,6 +675,7 @@ describe JSONAPI::Serializer do
|
|
645
675
|
'included' => [],
|
646
676
|
})
|
647
677
|
end
|
678
|
+
|
648
679
|
it 'handles include of to-many relationships with compound document' do
|
649
680
|
long_comments = create_list(:long_comment, 2)
|
650
681
|
post = create(:post, :with_author, long_comments: long_comments)
|
@@ -661,6 +692,7 @@ describe JSONAPI::Serializer do
|
|
661
692
|
],
|
662
693
|
})
|
663
694
|
end
|
695
|
+
|
664
696
|
it 'only includes one copy of each referenced relationship' do
|
665
697
|
long_comment = create(:long_comment)
|
666
698
|
long_comments = [long_comment, long_comment]
|
@@ -677,6 +709,7 @@ describe JSONAPI::Serializer do
|
|
677
709
|
],
|
678
710
|
})
|
679
711
|
end
|
712
|
+
|
680
713
|
it 'handles circular-referencing relationships with compound document' do
|
681
714
|
long_comments = create_list(:long_comment, 2)
|
682
715
|
post = create(:post, :with_author, long_comments: long_comments)
|
@@ -696,10 +729,12 @@ describe JSONAPI::Serializer do
|
|
696
729
|
],
|
697
730
|
})
|
698
731
|
end
|
732
|
+
|
699
733
|
it 'errors if include is not a defined attribute' do
|
700
734
|
user = create(:user)
|
701
735
|
expect { JSONAPI::Serializer.serialize(user, include: ['fake-attr']) }.to raise_error
|
702
736
|
end
|
737
|
+
|
703
738
|
it 'handles recursive loading of relationships' do
|
704
739
|
user = create(:user)
|
705
740
|
long_comments = create_list(:long_comment, 2, user: user)
|
@@ -737,6 +772,7 @@ describe JSONAPI::Serializer do
|
|
737
772
|
expect(actual_data['included']).to eq(expected_data['included'])
|
738
773
|
expect(actual_data).to eq(expected_data)
|
739
774
|
end
|
775
|
+
|
740
776
|
it 'handles recursive loading of multiple to-one relationships on children' do
|
741
777
|
first_user = create(:user)
|
742
778
|
second_user = create(:user)
|
@@ -774,6 +810,7 @@ describe JSONAPI::Serializer do
|
|
774
810
|
expect(actual_data['included']).to eq(expected_data['included'])
|
775
811
|
expect(actual_data).to eq(expected_data)
|
776
812
|
end
|
813
|
+
|
777
814
|
it 'includes linkage in compounded resources only if the immediate parent was also included' do
|
778
815
|
comment_user = create(:user)
|
779
816
|
long_comments = [create(:long_comment, user: comment_user)]
|
@@ -802,6 +839,7 @@ describe JSONAPI::Serializer do
|
|
802
839
|
expect(actual_data['included']).to eq(expected_data['included'])
|
803
840
|
expect(actual_data).to eq(expected_data)
|
804
841
|
end
|
842
|
+
|
805
843
|
it 'handles recursive loading of to-many relationships with overlapping include paths' do
|
806
844
|
user = create(:user)
|
807
845
|
long_comments = create_list(:long_comment, 2, user: user)
|
@@ -884,6 +922,7 @@ describe JSONAPI::Serializer do
|
|
884
922
|
}
|
885
923
|
})
|
886
924
|
end
|
925
|
+
|
887
926
|
it 'allows to limit fields(relationships) for serialized resource' do
|
888
927
|
first_user = create(:user)
|
889
928
|
second_user = create(:user)
|
@@ -909,6 +948,7 @@ describe JSONAPI::Serializer do
|
|
909
948
|
}
|
910
949
|
})
|
911
950
|
end
|
951
|
+
|
912
952
|
it "allows also to pass specific fields as array instead of comma-separates values" do
|
913
953
|
first_user = create(:user)
|
914
954
|
second_user = create(:user)
|
@@ -930,6 +970,7 @@ describe JSONAPI::Serializer do
|
|
930
970
|
}
|
931
971
|
})
|
932
972
|
end
|
973
|
+
|
933
974
|
it 'allows to limit fields(attributes and relationships) for included resources' do
|
934
975
|
first_user = create(:user)
|
935
976
|
second_user = create(:user)
|
@@ -983,18 +1024,21 @@ describe JSONAPI::Serializer do
|
|
983
1024
|
result = JSONAPI::Serializer.send(:parse_relationship_paths, [])
|
984
1025
|
expect(result).to eq({})
|
985
1026
|
end
|
1027
|
+
|
986
1028
|
it 'correctly handles single-level relationship paths' do
|
987
1029
|
result = JSONAPI::Serializer.send(:parse_relationship_paths, ['foo'])
|
988
1030
|
expect(result).to eq({
|
989
1031
|
'foo' => {_include: true}
|
990
1032
|
})
|
991
1033
|
end
|
1034
|
+
|
992
1035
|
it 'correctly handles multi-level relationship paths' do
|
993
1036
|
result = JSONAPI::Serializer.send(:parse_relationship_paths, ['foo.bar'])
|
994
1037
|
expect(result).to eq({
|
995
1038
|
'foo' => {_include: true, 'bar' => {_include: true}}
|
996
1039
|
})
|
997
1040
|
end
|
1041
|
+
|
998
1042
|
it 'correctly handles multi-level relationship paths with same parent' do
|
999
1043
|
paths = ['foo', 'foo.bar']
|
1000
1044
|
result = JSONAPI::Serializer.send(:parse_relationship_paths, paths)
|
@@ -1002,6 +1046,7 @@ describe JSONAPI::Serializer do
|
|
1002
1046
|
'foo' => {_include: true, 'bar' => {_include: true}}
|
1003
1047
|
})
|
1004
1048
|
end
|
1049
|
+
|
1005
1050
|
it 'correctly handles multi-level relationship paths with different parent' do
|
1006
1051
|
paths = ['foo', 'bar', 'bar.baz']
|
1007
1052
|
result = JSONAPI::Serializer.send(:parse_relationship_paths, paths)
|
@@ -1010,6 +1055,7 @@ describe JSONAPI::Serializer do
|
|
1010
1055
|
'bar' => {_include: true, 'baz' => {_include: true}},
|
1011
1056
|
})
|
1012
1057
|
end
|
1058
|
+
|
1013
1059
|
it 'correctly handles three-leveled path' do
|
1014
1060
|
paths = ['foo', 'foo.bar', 'foo.bar.baz']
|
1015
1061
|
result = JSONAPI::Serializer.send(:parse_relationship_paths, paths)
|
@@ -1017,6 +1063,7 @@ describe JSONAPI::Serializer do
|
|
1017
1063
|
'foo' => {_include: true, 'bar' => {_include: true, 'baz' => {_include: true}}}
|
1018
1064
|
})
|
1019
1065
|
end
|
1066
|
+
|
1020
1067
|
it 'correctly handles three-leveled path with skipped middle' do
|
1021
1068
|
paths = ['foo', 'foo.bar.baz']
|
1022
1069
|
result = JSONAPI::Serializer.send(:parse_relationship_paths, paths)
|
@@ -1025,6 +1072,7 @@ describe JSONAPI::Serializer do
|
|
1025
1072
|
})
|
1026
1073
|
end
|
1027
1074
|
end
|
1075
|
+
|
1028
1076
|
describe 'if/unless handling with contexts' do
|
1029
1077
|
it 'can be used to show/hide attributes' do
|
1030
1078
|
post = create(:post)
|
@@ -1068,6 +1116,7 @@ describe JSONAPI::Serializer do
|
|
1068
1116
|
expect(data['data']['attributes']).to_not have_key('body')
|
1069
1117
|
end
|
1070
1118
|
end
|
1119
|
+
|
1071
1120
|
describe 'context' do
|
1072
1121
|
it 'is passed through all relationship serializers' do
|
1073
1122
|
# Force long_comments to be serialized by the context-sensitive serializer.
|
@@ -1113,6 +1162,7 @@ describe JSONAPI::Serializer do
|
|
1113
1162
|
'related' => '/posts/1/author'
|
1114
1163
|
})
|
1115
1164
|
end
|
1165
|
+
|
1116
1166
|
it 'adds base_url to links if passed' do
|
1117
1167
|
long_comments = create_list(:long_comment, 1)
|
1118
1168
|
post = create(:post, long_comments: long_comments)
|
@@ -1123,6 +1173,7 @@ describe JSONAPI::Serializer do
|
|
1123
1173
|
'related' => 'http://example.com/posts/1/author'
|
1124
1174
|
})
|
1125
1175
|
end
|
1176
|
+
|
1126
1177
|
it 'uses overriden base_url method if it exists' do
|
1127
1178
|
long_comments = create_list(:long_comment, 1)
|
1128
1179
|
post = create(:post, long_comments: long_comments)
|
@@ -1233,4 +1284,54 @@ describe JSONAPI::Serializer do
|
|
1233
1284
|
expect(actual_data).to eq(expected_data)
|
1234
1285
|
end
|
1235
1286
|
end
|
1287
|
+
|
1288
|
+
describe 'instrumentation' do
|
1289
|
+
let(:post) { create(:post, :with_author) }
|
1290
|
+
let(:events) { [] }
|
1291
|
+
|
1292
|
+
before do
|
1293
|
+
ActiveSupport::Notifications.subscribe(notification_name) do |*args|
|
1294
|
+
events << ActiveSupport::Notifications::Event.new(*args)
|
1295
|
+
end
|
1296
|
+
end
|
1297
|
+
|
1298
|
+
describe 'serialize_primary' do
|
1299
|
+
let(:notification_name) { 'render.jsonapi_serializers.serialize_primary' }
|
1300
|
+
|
1301
|
+
it 'sends an event for a single serialize call' do
|
1302
|
+
JSONAPI::Serializer.serialize(post)
|
1303
|
+
|
1304
|
+
expect(events.length).to eq(1)
|
1305
|
+
expect(events[0].name).to eq(notification_name)
|
1306
|
+
expect(events[0].payload).to eq({class_name: "MyApp::Post"})
|
1307
|
+
end
|
1308
|
+
|
1309
|
+
it 'sends events for includes' do
|
1310
|
+
JSONAPI::Serializer.serialize(post, include: ['author'])
|
1311
|
+
|
1312
|
+
expect(events.length).to eq(2)
|
1313
|
+
expect(events[0].payload).to eq({class_name: "MyApp::Post"})
|
1314
|
+
expect(events[1].payload).to eq({class_name: "MyApp::User"})
|
1315
|
+
end
|
1316
|
+
end
|
1317
|
+
|
1318
|
+
describe 'find_recursive_relationships' do
|
1319
|
+
let(:notification_name) { 'render.jsonapi_serializers.find_recursive_relationships' }
|
1320
|
+
|
1321
|
+
it 'does not send event when there are no includes' do
|
1322
|
+
JSONAPI::Serializer.serialize(post)
|
1323
|
+
expect(events.length).to eq(0)
|
1324
|
+
end
|
1325
|
+
|
1326
|
+
it 'sends events for includes' do
|
1327
|
+
JSONAPI::Serializer.serialize(post, include: ['author'])
|
1328
|
+
|
1329
|
+
expect(events.length).to eq(2)
|
1330
|
+
expect(events[0].name).to eq(notification_name)
|
1331
|
+
expect(events[0].payload).to eq({class_name: "MyApp::User"})
|
1332
|
+
expect(events[1].name).to eq(notification_name)
|
1333
|
+
expect(events[1].payload).to eq({class_name: "MyApp::Post"})
|
1334
|
+
end
|
1335
|
+
end
|
1336
|
+
end
|
1236
1337
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jsonapi-serializers
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0.pre.beta.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Fotinakis
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-11-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -94,6 +94,20 @@ dependencies:
|
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '4.2'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: pry
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
97
111
|
description: Pure Ruby readonly serializers for the JSON:API spec.
|
98
112
|
email:
|
99
113
|
- mike@fotinakis.com
|
@@ -132,12 +146,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
132
146
|
version: '0'
|
133
147
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
134
148
|
requirements:
|
135
|
-
- - "
|
149
|
+
- - ">"
|
136
150
|
- !ruby/object:Gem::Version
|
137
|
-
version:
|
151
|
+
version: 1.3.1
|
138
152
|
requirements: []
|
139
|
-
|
140
|
-
rubygems_version: 2.7.6
|
153
|
+
rubygems_version: 3.0.4
|
141
154
|
signing_key:
|
142
155
|
specification_version: 4
|
143
156
|
summary: Pure Ruby readonly serializers for the JSON:API spec.
|