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 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