jbuilder-json_api 0.0.1 → 1.0.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: 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