jbuilder-json_api 0.0.1 → 1.0.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: 1ff4461806b35c5a3d74588a69c25b2114cb229f
4
- data.tar.gz: 14b6437c8ca3707ee94b7ecea417655976fb06d8
3
+ metadata.gz: bc772003535f958b77e4eca0eca1f9d7daa901bf
4
+ data.tar.gz: aef3eb54b4d987dc446dc548cd679af965fe692f
5
5
  SHA512:
6
- metadata.gz: 243d498cce513d4794dfa8babe42ee888f102b5dd328679bf923873597d5c4232425bcb67d329ed5a69ef3808e244066466b4133412b27709ee847ba21d23fc0
7
- data.tar.gz: 297d98968a8d93e6628f309e5b21ad9954216327dca0d4962405233c540496f60a588d60a7cca8ba1ce226ecca74d1a356012fe8f42781d54c50e9d14e78b733
6
+ metadata.gz: 5153c6bda708041667eef1daf765a93ed8f148518fe0f0904d2fbcd969468ad4ecb83219710502433f1c81da32b61c5c9eb48d19c1ee03ecfbd3e90f3e2cbf31
7
+ data.tar.gz: 4b23517ae45d402b430595420d6845d96f460027700116f2dbbc21177bee1de5f0498d177d4fe34ef66e5a9dfa7aacd33754f6e11e6ec786022a77bac83cc581
data/README.md CHANGED
@@ -1,13 +1,15 @@
1
- # Jbuilder::JsonApi | [![Build Status](https://travis-ci.org/vladfaust/jbuilder-json_api.svg?branch=master)](https://travis-ci.org/vladfaust/jbuilder-json_api) [![Code Climate](https://codeclimate.com/github/vladfaust/jbuilder-json_api/badges/gpa.svg)](https://codeclimate.com/github/vladfaust/jbuilder-json_api) [![Test Coverage](https://codeclimate.com/github/vladfaust/jbuilder-json_api/badges/coverage.svg)](https://codeclimate.com/github/vladfaust/jbuilder-json_api/coverage)
1
+ # Jbuilder::JsonApi | [![Gem Version](https://badge.fury.io/rb/jbuilder-json_api.svg)](https://badge.fury.io/rb/jbuilder-json_api) ![](http://ruby-gem-downloads-badge.herokuapp.com/jbuilder-json_api?color=brightgreen) [![Build Status](https://travis-ci.org/vladfaust/jbuilder-json_api.svg?branch=master)](https://travis-ci.org/vladfaust/jbuilder-json_api) [![Dependency Status](https://gemnasium.com/vladfaust/jbuilder-json_api.svg)](https://gemnasium.com/vladfaust/jbuilder-json_api)
2
2
 
3
3
  Adds a `json.api_format!(resources)` method to quickly represent a resource or collection in a valid [JSON API](http://jsonapi.org/) format without any new superclasses or weird setups. Set'n'go! :rocket:
4
4
 
5
5
  ## Motivation
6
6
 
7
- Official JSON API [implementations page](http://jsonapi.org/implementations/#server-libraries-ruby) shows us a variety of different serializers and other heavy-weight stuff. I' in love with [Jbuilder](https://github.com/rails/jbuilder), as it allows to format json responses with ease. Therefore I wanted to connect Jbuilder and JsonApi.org specs.
7
+ Official JSON API [implementations page](http://jsonapi.org/implementations/#server-libraries-ruby) shows us a variety of different serializers and other heavy-weight stuff. I'm in love with [Jbuilder](https://github.com/rails/jbuilder), as it allows to format json responses with ease. Therefore I wanted to connect Jbuilder and JsonApi.org specs.
8
8
 
9
9
  I'd like to notice that there already is one gem called [jbuilder-jsonapi](https://github.com/csexton/jbuilder-jsonapi) by [csexton](https://github.com/csexton), but it adds a links helper only. It's not enough for me! :facepunch:
10
10
 
11
+ As a result, I've created a **very** lightweight & flexible solution - all you need is Jbuilder and this gem. Then you should delete everything within your `*.json.jbuilder` files and replace it with below recommendations (just one line! :flushed:). After you are free to customize parsed attributes and relationships with three tiny methods.
12
+
11
13
  ## Installation
12
14
 
13
15
  Add this line to your application's Gemfile:
@@ -29,10 +31,13 @@ Or install it yourself as:
29
31
  Replace any content within any `*.json.jbuilder` file with the code below:
30
32
  ```ruby
31
33
  # Common example
32
- json.api_format! @resources, @errors, meta: @meta, access_level: @user_access_level
34
+ json.api_format! @resources, @errors, meta, options
35
+
36
+ # Items example
37
+ json.api_format! @items, @errors, nil, access_level: :admin
33
38
 
34
- # Articles w/o meta or access levels example
35
- json.api_format! @articles, @errors
39
+ # A simple items example
40
+ json.api_format! @items
36
41
  ```
37
42
  You can also render formatted JSON straight from controller actions:
38
43
  ```ruby
@@ -41,24 +46,24 @@ respond_to do |f|
41
46
  f.html { render nothing: true, status: :bad_request }
42
47
  end
43
48
  ```
44
- Each resource instance, as well as the included one, will be invoked with `json_api_attrs` & `json_api_relations` methods. These methods **MAY** be implemented within each model. `api_format!` method will try to get an object's permitted (**you are free do define authentication logic yourself!**) attributes and relations via those two methods.
49
+ Each resource instance, as well as the included one, will be invoked with `json_api_attrs (options)`, `json_api_relations (options)` & `json_api_meta (options)` methods. These methods **MAY** be implemented within each model. `api_format!` method will try to get an object's permitted attributes (**remember, you are free do define authentication logic yourself!**) and relations and meta information via those three methods.
45
50
 
46
51
  Here is an example of implementation:
47
52
  ```ruby
48
- # Item model
53
+ # Inside Item model
49
54
 
50
- def json_api_attr (access_level = nil)
55
+ def json_api_attrs (options = {})
51
56
  attrs = []
52
- attrs += %w(name description price buyoutable item_type category) if %i(user admin).include?access_level
53
- attrs += %w(real_price in_stock) if access_level == :admin
57
+ attrs += %w(name description price buyoutable item_type category) if %i(user admin).include?options[:access_level]
58
+ attrs += %w(real_price in_stock) if options[:access_level] == :admin
54
59
  attrs
55
60
  end
56
61
 
57
- def json_api_relations (access_level = nil)
62
+ def json_api_relations (options = {})
58
63
  %w(category orders)
59
64
  end
60
65
  ```
61
- **Note** that the gem will call methods pulled with `json_api_relations and _attrs`. As for the above example, methods like `:name`, `:description`, `:orders` will be invoked for an Item instance. And yes, relations are fetched properly if an object responds to `orders`.
66
+ **Note** that the gem will call methods pulled via `json_api_relations and _attrs`. As for the above example, methods like `:name`, `:description`, `:real_price`, `:orders` will be invoked for an Item instance. And yes, relations are fetched properly and recursively if the object responds to `orders`.
62
67
 
63
68
  ## Development
64
69
 
@@ -73,5 +78,17 @@ Bug reports and pull requests are welcome on GitHub at [https://github.com/vladf
73
78
  ## ToDo
74
79
 
75
80
  - [ ] Maybe add `Content-Type: application/vnd.api+json`. This spec is ignored right now :smirk:
76
- - [ ] Add links tests
77
- - [ ] Somehow implement `[fields]` parameter
81
+ - [ ] Add links tests and improve them. Links now work only within views (where `@context` is present).
82
+ - [ ] Somehow implement `[fields]` parameter
83
+
84
+ ## Versions
85
+
86
+ #### 0.0.1 -> 1.0.0
87
+
88
+ **Breaking:**
89
+ - [x] Now any value can be forwarded to resources' methods via last `options` argument.
90
+ - [x] Added third argument `meta`, which is used to show meta information in the context of request
91
+
92
+ **Not breaking:**
93
+ - [x] Added support for `json_api_meta (options)` method.
94
+ - [x] Any internal error is now properly handled.
@@ -5,84 +5,91 @@ module JsonAPI
5
5
  # Returns a valid-formatted JSON which follows JSON-API specifications:
6
6
  # http://jsonapi.org/
7
7
  #
8
- # Arguments:
9
- # :resources: - list of resources to render (may be even one or nil)
10
- # :errors: - array of errors in below format:
8
+ # ==== Arguments
9
+ # * +resources+ - list of resources to render (may be even one or nil);
10
+ # * +errors+ - array of hashes in the below format:
11
11
  # [{ status: 422, detail: 'This error occurs because...' }, {...}]
12
+ # * +meta+ - a hash representing any meta (additional) information.
12
13
  #
13
- # Options:
14
- # :access_level: - access level, e.g. nil, :user, :admin
15
- # :meta: - a hash representing meta (additional) information
14
+ # ==== Options
15
+ # Any information can be passed as +options+ argument; resources' class methods
16
+ # +json_api_attrs+, +json_api_relations+ and +json_api_meta+
17
+ # will be invoked with this argument.
16
18
  #
17
- def api_format! (resources = nil, errors = nil, options = {})
18
- options.merge access_level: nil
19
- options.merge meta: nil
20
-
21
- # Firstly, print meta
22
- # http://jsonapi.org/format/#document-meta
23
- #
24
- if options[:meta] && !options[:meta].empty?
25
- meta options[:meta]
26
- end
19
+ def api_format! (resources = nil, errors = nil, meta = nil, options = {})
20
+ begin
21
+ # Firstly, print meta
22
+ # http://jsonapi.org/format/#document-meta
23
+ #
24
+ if meta && !meta.empty?
25
+ meta meta
26
+ end
27
+
28
+ # Secondly, take care of errors. If there are any,
29
+ # no 'data' section should be represented.
30
+ # http://jsonapi.org/format/#document-top-level
31
+ #
32
+ # Read more at
33
+ # http://jsonapi.org/format/#errors
34
+ #
35
+ if errors && !errors.empty?
36
+ ignore_nil! true
37
+ errors errors do |error|
38
+ id error[:id]
39
+ status error[:status]
40
+ detail error[:detail]
41
+ code error[:code]
42
+ title error[:title]
43
+
44
+ if error[:source]
45
+ source do
46
+ pointer error[:source][:pointer]
47
+ paramater error[:source][:parameter]
48
+ end
49
+ end
27
50
 
28
- # Secondly, take care of errors. If there are any,
29
- # no 'data' section should be represented.
30
- # http://jsonapi.org/format/#document-top-level
31
- #
32
- # Read more at
33
- # http://jsonapi.org/format/#errors
34
- #
35
- if errors && !errors.empty?
36
- ignore_nil! (@ignore_nil.nil? ? true : @ignore_nil)
37
- errors errors do |error|
38
- id error[:id]
39
- status error[:status]
40
- detail error[:detail]
41
- code error[:code]
42
- title error[:title]
43
-
44
- source do
45
- pointer error[:pointer]
46
- paramater error[:parameter]
51
+ if error[:links]
52
+ links do
53
+ about error[:links][:about]
54
+ end
55
+ end
47
56
  end
57
+ return self
58
+ end
59
+
60
+ resources = [*resources]
48
61
 
62
+ # http://jsonapi.org/format/#document-links
63
+ #
64
+ if @context
49
65
  links do
50
- about error[:about]
66
+ set! 'self', @context.request.path
51
67
  end
52
68
  end
53
- return self
54
- end
55
-
56
- resources = ::Kernel::Array resources
57
69
 
58
- # http://jsonapi.org/format/#document-links
59
- #
60
- links do
61
- begin
62
- set! 'self', @context.request.path
63
- rescue
64
- # No @context given, cannot find path
70
+ data do
71
+ resources.blank? ? array! : _api_resource_objects(resources, options)
65
72
  end
66
- end
67
73
 
68
- data do
69
- resources.blank? ? array! : _api_resource_objects(resources, options[:access_level])
70
- end
74
+ included = []
75
+ resources.each do |resource|
76
+ next unless resource.respond_to?'json_api_relations'
77
+ resource.json_api_relations(options).each do |relationship|
78
+ included += [*(resource.send(relationship))]
79
+ end
80
+ end
81
+ included.uniq!
71
82
 
72
- included = []
73
- resources.each do |resource|
74
- next unless resource.respond_to?'json_api_relations'
75
- resource.json_api_relations(options[:access_level]).each do |relationship|
76
- included += ::Kernel::Array(resource.send(relationship))
83
+ included do
84
+ _api_resource_objects(included, options, resources) unless included.blank?
77
85
  end
78
- end
79
- included.uniq!
80
86
 
81
- included do
82
- _api_resource_objects(included, options[:access_level], resources) unless included.blank?
87
+ self
88
+ rescue Exception => e
89
+ @attributes = {}
90
+ message = Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.3.0') ? e.original_message : e.message
91
+ return api_format! nil, [{ status: 500, title: e.class.to_s, detail: message }]
83
92
  end
84
-
85
- self
86
93
  end
87
94
 
88
95
  private
@@ -90,7 +97,7 @@ module JsonAPI
90
97
  # Formats a resources array properly
91
98
  # http://jsonapi.org/format/#document-resource-objects
92
99
  #
93
- def _api_resource_objects (resources, access_level, parent_resources = nil)
100
+ def _api_resource_objects (resources, options, parent_resources = nil)
94
101
  resources.each do |resource|
95
102
  child! do
96
103
  type resource.class.name.demodulize.to_s.downcase
@@ -100,7 +107,7 @@ module JsonAPI
100
107
  #
101
108
  if resource.respond_to?'json_api_attrs'
102
109
  attributes do
103
- resource.json_api_attrs(access_level).each do |attribute|
110
+ resource.json_api_attrs(options).each do |attribute|
104
111
  set! attribute, resource.send(attribute)
105
112
  end
106
113
  end
@@ -109,21 +116,19 @@ module JsonAPI
109
116
  # http://jsonapi.org/format/#document-resource-object-relationships
110
117
  #
111
118
  if resource.respond_to?'json_api_relations'
112
- unless resource.json_api_relations(access_level).blank?
119
+ unless resource.json_api_relations(options).blank?
113
120
  relationships do
114
- resource.json_api_relations(access_level).each do |relationship|
121
+ resource.json_api_relations(options).each do |relationship|
115
122
  set! relationship do
116
- links do
117
- begin
123
+ if @context
124
+ links do
118
125
  related @context.send("#{ relationship.pluralize }_path")
119
- rescue
120
- # No @context given, cannot find path
126
+ # TODO add a link to the relationship itself
121
127
  end
122
- # TODO add a link to the relationship itself
123
128
  end
124
129
 
125
130
  data do
126
- ::Kernel::Array(resource.send(relationship)).each do |relationship_instance|
131
+ [*(resource.send(relationship))].each do |relationship_instance|
127
132
  # Relationships shouldn't ever link to the parent resource
128
133
  #
129
134
  next if !parent_resources.nil? && parent_resources.include?(relationship_instance)
@@ -139,11 +144,16 @@ module JsonAPI
139
144
  end
140
145
  end
141
146
 
142
- links do
143
- begin
147
+ if resource.respond_to?'json_api_meta'
148
+ # We don't want to see 'meta': null
149
+ ignore_nil! true
150
+ meta resource.json_api_meta(options)
151
+ ignore_nil! @ignore_nil
152
+ end
153
+
154
+ if @context
155
+ links do
144
156
  set! 'self', @context.send("#{ resource.class.name.demodulize.to_s.downcase }_path", resource)
145
- rescue
146
- # No @context given, cannot find path
147
157
  end
148
158
  end
149
159
  end
@@ -1,3 +1,3 @@
1
1
  module JsonAPI
2
- VERSION = '0.0.1'
2
+ VERSION = '1.0.0'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jbuilder-json_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vlad Faust