jsonapi-serializers 1.0.1 → 2.0.0.pre.beta.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.
- 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.
|