jsonapi-serializers 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|