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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 42699af4d36a1e0a2293c857393c2dc3536d8d82
4
- data.tar.gz: 92ef3e0b867d350c32fe4145c01958e38ceb2a8b
3
+ metadata.gz: f3b9ea3fd617b920688a8694e6d2a923c39de458
4
+ data.tar.gz: e5fd7307ab8acd411c31e96a4fab0f4e82b25a93
5
5
  SHA512:
6
- metadata.gz: 06c90bbb58c2910078140c46592ee8f6ce81d20504b530e1ca853484b7573a198fd1da7e2f98d54cbb8f76eb471eda50cc41599b5e99cd76733c6e66a7280c57
7
- data.tar.gz: 696761f2e0863825c0b232d506795758e4eda93a166d32f05095e59b412cde1531dc992e7c89e83afe86b1b568712a57fd9bb5a44d4fad628f181022a4b290c4
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.fetch(:serializer)
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.
@@ -1,5 +1,5 @@
1
1
  module JSONAPI
2
2
  module Serializer
3
- VERSION = '0.5.0'
3
+ VERSION = '0.6.0'
4
4
  end
5
5
  end
@@ -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
@@ -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 }
@@ -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.5.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-01-30 00:00:00.000000000 Z
11
+ date: 2016-02-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport