jsonapi-serializers 0.5.0 → 0.6.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/README.md +100 -0
- data/lib/jsonapi-serializers/attributes.rb +11 -0
- data/lib/jsonapi-serializers/serializer.rb +1 -3
- data/lib/jsonapi-serializers/version.rb +1 -1
- data/spec/serializer_spec.rb +61 -0
- data/spec/support/factory.rb +13 -0
- data/spec/support/serializers.rb +15 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f3b9ea3fd617b920688a8694e6d2a923c39de458
|
4
|
+
data.tar.gz: e5fd7307ab8acd411c31e96a4fab0f4e82b25a93
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5c4ac246ad0366b5d3cdfb165a62982b79e3f9a36d2762fff3feb404f6ef3adfd1b22f2fe88e6651d421ecd52406a6c458d73c87fe29e66fb80c3a86e5a5847e
|
7
|
+
data.tar.gz: 4c7c6b9793a408ad4ca7cbc1bc504654817900a57ecb2cbaf190c900864c5a04391df1a983b0229cc0925d908a8ed49b69b98ff3684e7d3c07dcd225bc4eaaa5
|
data/README.md
CHANGED
@@ -24,6 +24,7 @@ This library is up-to-date with the finalized v1 JSON API spec.
|
|
24
24
|
* [Compound documents and includes](#compound-documents-and-includes)
|
25
25
|
* [Relationship path handling](#relationship-path-handling)
|
26
26
|
* [Rails example](#rails-example)
|
27
|
+
* [Sinatra example](#sinatra-example)
|
27
28
|
* [Unfinished business](#unfinished-business)
|
28
29
|
* [Contributing](#contributing)
|
29
30
|
|
@@ -540,6 +541,104 @@ ActionDispatch::Http::Parameters::DEFAULT_PARSERS[Mime::Type.lookup(JSONAPI::MIM
|
|
540
541
|
end
|
541
542
|
```
|
542
543
|
|
544
|
+
## Sinatra example
|
545
|
+
|
546
|
+
Using [Sequel ORM](http://sequel.jeremyevans.net) instead of ActiveRecord. The
|
547
|
+
important things to note here are the `:tactical_eager_loading` plugin, which
|
548
|
+
will greatly reduce the number of queries performed when sideloading related
|
549
|
+
records, and the `:skip_collection_check` option that must be set to true in
|
550
|
+
order for `JSONAPI::Serializer.serialize` to be able to serialize single
|
551
|
+
Sequel::Model instances.
|
552
|
+
|
553
|
+
```ruby
|
554
|
+
require 'sequel'
|
555
|
+
require 'sinatra/base'
|
556
|
+
require 'json/ext'
|
557
|
+
require 'jsonapi-serializers'
|
558
|
+
|
559
|
+
class Post < Sequel::Model
|
560
|
+
plugin :tactical_eager_loading
|
561
|
+
|
562
|
+
one_to_many :comments
|
563
|
+
end
|
564
|
+
|
565
|
+
class Comment < Sequel::Model
|
566
|
+
many_to_one :post
|
567
|
+
end
|
568
|
+
|
569
|
+
class BaseSerializer
|
570
|
+
include JSONAPI::Serializer
|
571
|
+
|
572
|
+
def self_link
|
573
|
+
"/api/v1#{super}"
|
574
|
+
end
|
575
|
+
end
|
576
|
+
|
577
|
+
class PostSerializer < BaseSerializer
|
578
|
+
attribute :title
|
579
|
+
attribute :content
|
580
|
+
|
581
|
+
has_many :comments
|
582
|
+
end
|
583
|
+
|
584
|
+
class CommentSerializer < BaseSerializer
|
585
|
+
attribute :username
|
586
|
+
attribute :body
|
587
|
+
|
588
|
+
has_one :post
|
589
|
+
end
|
590
|
+
|
591
|
+
module Api
|
592
|
+
class V1 < Sinatra::Base
|
593
|
+
configure do
|
594
|
+
mime_type :jsonapi, 'application/vnd.api+json'
|
595
|
+
|
596
|
+
set :database, Sequel.connect
|
597
|
+
end
|
598
|
+
|
599
|
+
helpers do
|
600
|
+
# Parse the body of the request depending on its content-type:
|
601
|
+
def parse_request_body
|
602
|
+
request.body.rewind
|
603
|
+
|
604
|
+
case request.content_type
|
605
|
+
when /json$/, /javascript$/
|
606
|
+
JSON.parse(request.body.read, symbolize_names: true)
|
607
|
+
end
|
608
|
+
end
|
609
|
+
|
610
|
+
# Convenience methods for serializing models:
|
611
|
+
def serialize_model(model, options = {})
|
612
|
+
options[:is_collection] = false
|
613
|
+
options[:skip_collection_check] = true
|
614
|
+
JSONAPI::Serializer.serialize(model, options)
|
615
|
+
end
|
616
|
+
|
617
|
+
def serialize_models(models, options = {})
|
618
|
+
options[:is_collection] = true
|
619
|
+
JSONAPI::Serializer.serialize(models, options)
|
620
|
+
end
|
621
|
+
end
|
622
|
+
|
623
|
+
before do
|
624
|
+
@data = parse_request_body if request.body.size > 0
|
625
|
+
end
|
626
|
+
|
627
|
+
get '/posts', provides: :jsonapi do
|
628
|
+
posts = Post.all
|
629
|
+
not_found if posts.empty?
|
630
|
+
serialize_models(posts).to_json
|
631
|
+
end
|
632
|
+
|
633
|
+
get '/posts/:id', provides: :jsonapi do
|
634
|
+
post = Post[params[:id]]
|
635
|
+
not_found if post.nil?
|
636
|
+
serialize_model(post, include: 'comments').to_json
|
637
|
+
end
|
638
|
+
end
|
639
|
+
end
|
640
|
+
```
|
641
|
+
|
543
642
|
## Unfinished business
|
544
643
|
|
545
644
|
* Support for passing `context` through to serializers is partially complete, but needs more work.
|
@@ -549,6 +648,7 @@ end
|
|
549
648
|
|
550
649
|
## Release notes
|
551
650
|
|
651
|
+
* v0.6.0: Support for polymorphic collections and inheriting serializer attributes.
|
552
652
|
* v0.5.0: Support for explicit serializer discovery.
|
553
653
|
* v0.4.0: Support for declaring multiple `attributes`.
|
554
654
|
* v0.3.1: Improve performance of loading included relationships.
|
@@ -3,6 +3,17 @@ module JSONAPI
|
|
3
3
|
def self.included(target)
|
4
4
|
target.send(:include, InstanceMethods)
|
5
5
|
target.extend ClassMethods
|
6
|
+
|
7
|
+
target.class_eval do
|
8
|
+
def self.inherited(target)
|
9
|
+
[:attributes_map, :to_one_associations, :to_many_associations]
|
10
|
+
.each{|k|
|
11
|
+
key = "@#{k}"
|
12
|
+
attr = self.instance_variable_get(key)
|
13
|
+
target.instance_variable_set(key, attr.dup) if attr
|
14
|
+
}
|
15
|
+
end
|
16
|
+
end
|
6
17
|
end
|
7
18
|
|
8
19
|
module InstanceMethods
|
@@ -269,7 +269,6 @@ module JSONAPI
|
|
269
269
|
primary_data = nil
|
270
270
|
elsif options[:is_collection]
|
271
271
|
# Have object collection.
|
272
|
-
passthrough_options[:serializer] ||= find_serializer_class(objects.first)
|
273
272
|
primary_data = serialize_primary_multi(objects, passthrough_options)
|
274
273
|
else
|
275
274
|
# Duck-typing check for a collection being passed without is_collection true.
|
@@ -280,7 +279,6 @@ module JSONAPI
|
|
280
279
|
'Must provide `is_collection: true` to `serialize` when serializing collections.')
|
281
280
|
end
|
282
281
|
# Have single object.
|
283
|
-
passthrough_options[:serializer] ||= find_serializer_class(objects)
|
284
282
|
primary_data = serialize_primary(objects, passthrough_options)
|
285
283
|
end
|
286
284
|
result = {
|
@@ -314,7 +312,7 @@ module JSONAPI
|
|
314
312
|
end
|
315
313
|
|
316
314
|
def self.serialize_primary(object, options = {})
|
317
|
-
serializer_class = options
|
315
|
+
serializer_class = options[:serializer] || find_serializer_class(object)
|
318
316
|
|
319
317
|
# Spec: Primary data MUST be either:
|
320
318
|
# - a single resource object or null, for requests that target single resources.
|
data/spec/serializer_spec.rb
CHANGED
@@ -323,6 +323,35 @@ describe JSONAPI::Serializer do
|
|
323
323
|
},
|
324
324
|
})
|
325
325
|
end
|
326
|
+
it 'can find the correct serializer by object class name' do
|
327
|
+
post = create(:post)
|
328
|
+
primary_data = serialize_primary(post)
|
329
|
+
expect(primary_data).to eq({
|
330
|
+
'id' => '1',
|
331
|
+
'type' => 'posts',
|
332
|
+
'attributes' => {
|
333
|
+
'title' => 'Title for Post 1',
|
334
|
+
'long-content' => 'Body for Post 1',
|
335
|
+
},
|
336
|
+
'links' => {
|
337
|
+
'self' => '/posts/1',
|
338
|
+
},
|
339
|
+
'relationships' => {
|
340
|
+
'author' => {
|
341
|
+
'links' => {
|
342
|
+
'self' => '/posts/1/relationships/author',
|
343
|
+
'related' => '/posts/1/author',
|
344
|
+
},
|
345
|
+
},
|
346
|
+
'long-comments' => {
|
347
|
+
'links' => {
|
348
|
+
'self' => '/posts/1/relationships/long-comments',
|
349
|
+
'related' => '/posts/1/long-comments',
|
350
|
+
},
|
351
|
+
},
|
352
|
+
},
|
353
|
+
})
|
354
|
+
end
|
326
355
|
end
|
327
356
|
|
328
357
|
describe 'JSONAPI::Serializer.serialize' do
|
@@ -768,4 +797,36 @@ describe JSONAPI::Serializer do
|
|
768
797
|
})
|
769
798
|
end
|
770
799
|
end
|
800
|
+
|
801
|
+
describe 'inheritance through subclassing' do
|
802
|
+
it 'inherits attributes' do
|
803
|
+
tagged_post = create(:tagged_post)
|
804
|
+
options = {serializer: MyApp::PostSerializerWithInheritedProperties}
|
805
|
+
data = JSONAPI::Serializer.serialize(tagged_post, options);
|
806
|
+
expect(data['data']['attributes']['title']).to eq('Title for TaggedPost 1');
|
807
|
+
expect(data['data']['attributes']['tag']).to eq('Tag for TaggedPost 1');
|
808
|
+
end
|
809
|
+
|
810
|
+
it 'inherits relations' do
|
811
|
+
long_comments = create_list(:long_comment, 2)
|
812
|
+
tagged_post = create(:tagged_post, :with_author, long_comments: long_comments)
|
813
|
+
options = {serializer: MyApp::PostSerializerWithInheritedProperties}
|
814
|
+
data = JSONAPI::Serializer.serialize(tagged_post, options);
|
815
|
+
|
816
|
+
expect(data['data']['relationships']).to eq({
|
817
|
+
'author' => {
|
818
|
+
'links' => {
|
819
|
+
'self' => '/tagged-posts/1/relationships/author',
|
820
|
+
'related' => '/tagged-posts/1/author',
|
821
|
+
},
|
822
|
+
},
|
823
|
+
'long-comments' => {
|
824
|
+
'links' => {
|
825
|
+
'self' => '/tagged-posts/1/relationships/long-comments',
|
826
|
+
'related' => '/tagged-posts/1/long-comments',
|
827
|
+
}
|
828
|
+
}
|
829
|
+
})
|
830
|
+
end
|
831
|
+
end
|
771
832
|
end
|
data/spec/support/factory.rb
CHANGED
@@ -12,6 +12,19 @@ FactoryGirl.define do
|
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
+
# Post with some added property to test inheritance in serializer.
|
16
|
+
factory :tagged_post, class: MyApp::TaggedPost do
|
17
|
+
skip_create
|
18
|
+
sequence(:id) {|n| n }
|
19
|
+
sequence(:title) {|n| "Title for TaggedPost #{n}" }
|
20
|
+
sequence(:body) {|n| "Body for TaggedPost #{n}" }
|
21
|
+
sequence(:tag) {|n| "Tag for TaggedPost #{n}" }
|
22
|
+
|
23
|
+
trait :with_author do
|
24
|
+
association :author, factory: :user
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
15
28
|
factory :long_comment, class: MyApp::LongComment do
|
16
29
|
skip_create
|
17
30
|
sequence(:id) {|n| n }
|
data/spec/support/serializers.rb
CHANGED
@@ -7,6 +7,15 @@ module MyApp
|
|
7
7
|
attr_accessor :long_comments
|
8
8
|
end
|
9
9
|
|
10
|
+
class TaggedPost
|
11
|
+
attr_accessor :id
|
12
|
+
attr_accessor :title
|
13
|
+
attr_accessor :body
|
14
|
+
attr_accessor :tag
|
15
|
+
attr_accessor :author
|
16
|
+
attr_accessor :long_comments
|
17
|
+
end
|
18
|
+
|
10
19
|
class LongComment
|
11
20
|
attr_accessor :id
|
12
21
|
attr_accessor :body
|
@@ -138,6 +147,11 @@ module MyApp
|
|
138
147
|
|
139
148
|
attributes :title, :body
|
140
149
|
end
|
150
|
+
|
151
|
+
class PostSerializerWithInheritedProperties < PostSerializer
|
152
|
+
# Add only :tag, inherit the rest.
|
153
|
+
attribute :tag
|
154
|
+
end
|
141
155
|
end
|
142
156
|
|
143
157
|
# Test the `jsonapi_serializer_class_name` override method for serializers in different namespaces.
|
@@ -148,4 +162,4 @@ module MyAppOtherNamespace
|
|
148
162
|
|
149
163
|
attribute :name
|
150
164
|
end
|
151
|
-
end
|
165
|
+
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: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Fotinakis
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-02-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|