shamu 0.0.7 → 0.0.8

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: 17d15280c07fb25429f25d595d1f30f7a5509f52
4
- data.tar.gz: cf2f8593461815af79b589332bdc56569bef2de5
3
+ metadata.gz: afa18618f6ec75e4163bbc06c2ac89d60b5729d6
4
+ data.tar.gz: 0d3fc88e85d907868e82a98d8b877c326eacb4b9
5
5
  SHA512:
6
- metadata.gz: 4f954b06458d9728ccdd30636e478ab90e16cd24280a874fbf402c98bad9b59e67c1691895f80ee57643417f783bee7de16613bcdf0875b6cd036f94048798c9
7
- data.tar.gz: 13f497d44a24128bbe7e479547efcb3da461b72cf3d06fb0ec3c2dd8190b73ff0c79937debbae8bbef6c58c47ea45b2ca516ec0275876563d9728eb3620d9275
6
+ metadata.gz: 405509ea9020934875f4d74015c62b4733511b948c81caa617e67c94ffb3512dffd2264a8f8dcfcccd8277a2835eb142c6a84fb6edf090f6ed8dfdbd9aa8becf
7
+ data.tar.gz: af3f05ab6ac199ae75d9716d430ff3270eab6fc156f74a709ad87be0d70d7042fbcc8865cb5f660cdc60d1494657854b76a8c7e6fc10a2c0039ab98402cd6f35
@@ -1,9 +1,9 @@
1
1
  require "api_responder"
2
2
 
3
3
  class ApiController < ApplicationController
4
- include Shamu::Rails::JsonApi
4
+ include Shamu::JsonApi::Rails::Controller
5
5
 
6
6
  self.responder = ::ApiResponder
7
7
 
8
- respond_to :json, :json_api
8
+ respond_to :json_api, :json
9
9
  end
@@ -1,4 +1,4 @@
1
1
  class ApiResponder < ActionController::Responder
2
2
  include Responders::HttpCacheResponder
3
- include Shamu::Rails::JsonApiResponder
3
+ include Shamu::JsonApi::Rails::Responder
4
4
  end
@@ -1,6 +1,6 @@
1
1
  # Base {Shamu::JsonApi::Presenter} that all other presenters should
2
2
  # inherit from.
3
- class ApplicationPresenter < shamu::JsonApi::Presenter
3
+ class ApplicationPresenter < Shamu::JsonApi::Presenter
4
4
  include ::Rails.application.routes.url_helpers
5
5
 
6
6
  # Override default_url_options in config/environments files.
@@ -0,0 +1,220 @@
1
+ require "rack"
2
+
3
+ module Shamu
4
+ module JsonApi
5
+ module Rails
6
+
7
+ # Add support for writing resources as well-formed JSON API.
8
+ module Controller
9
+ extend ActiveSupport::Concern
10
+
11
+ included do
12
+ before_action do
13
+ render json: json_error( "The 'include' parameter is not supported" ), status: :bad_request if params[:include] # rubocop:disable Metrics/LineLength
14
+ request.formats = [ :json_api, :json ]
15
+ end
16
+ end
17
+
18
+ # def process_action( * )
19
+ # # If no format has been specfied, default to json_api
20
+ # request.parameters[:format] ||= "json_api"
21
+ # super
22
+ # end
23
+
24
+ # Builds a well-formed JSON API response for a single resource.
25
+ #
26
+ # @param [Object] resource to present as JSON.
27
+ # @param [Class] presenter {Presenter} class to use when building the
28
+ # response for the given resource. If not given, attempts to find a
29
+ # presenter by calling {Context#find_presenter}.
30
+ # @param (see #json_context)
31
+ # @yield (response) write additional top-level links and meta
32
+ # information.
33
+ # @yieldparam [JsonApi::Response] response
34
+ # @return [JsonApi::Response] the presented JSON response.
35
+ def json_resource( resource, presenter = nil, **context, &block )
36
+ response = build_json_response( context )
37
+ response.resource resource, presenter
38
+ yield response if block_given?
39
+ response.to_json
40
+ end
41
+
42
+ # Builds a well-formed JSON API response for a collection of resources.
43
+ #
44
+ # @param [Enumerable<Object>] resources to present as a JSON array.
45
+ # @param [Class] presenter {Presenter} class to use when building the
46
+ # response for each of the resources. If not given, attempts to find
47
+ # a presenter by calling {Context#find_presenter}
48
+ # @param (see #json_context)
49
+ # @yield (response) write additional top-level links and meta
50
+ # information.
51
+ # @yieldparam [JsonApi::Response] response
52
+ # @return [JsonApi::Response] the presented JSON response.
53
+ def json_collection( resources, presenter = nil, pagination: :auto, **context, &block )
54
+ response = build_json_response( context )
55
+ response.collection resources, presenter
56
+ json_paginate_resources response, resources, pagination
57
+ yield response if block_given?
58
+ response.to_json
59
+ end
60
+
61
+ # Write all the validation errors from a record to the response.
62
+ #
63
+ # @param (see Shamu::JsonApi::Response#validation_errors)
64
+ # @yield (builder, attr, message)
65
+ # @yieldparam (see Shamu::JsonApi::Response#validation_errors)
66
+ # @return [JsonApi::Response] the presented JSON response.
67
+ def json_validation_errors( errors, **context, &block )
68
+ response = build_json_response( context )
69
+ response.validation_errors errors, &block
70
+
71
+ response.to_json
72
+ end
73
+
74
+ private
75
+
76
+ # @!visibility public
77
+ #
78
+ # Add page-based pagination links for the resources to the builder.
79
+ #
80
+ # @param [#current_page,#next_page,#previous_page] resources a collection that responds to `#current_page`
81
+ # @param [JsonApi::BaseBuilder] builder to add links to.
82
+ # @param [String] param the name of the key page parameter to adjust
83
+ # @return [void]
84
+ def json_paginate( resources, builder, param: :page )
85
+ page = resources.current_page
86
+
87
+ if resources.respond_to?( :next_page ) ? resources.next_page : true
88
+ builder.link :next, url_for( json_page_parameter( param, :number, page + 1 ) )
89
+ end
90
+
91
+ if resources.respond_to?( :prev_page ) ? resources.prev_page : page > 1
92
+ builder.link :prev, url_for( json_page_parameter( param, :number, page - 1 ) )
93
+ end
94
+ end
95
+
96
+ def json_page_parameter( page_param_name, param, value )
97
+ page_params = params.reverse_merge page_param_name => {}
98
+ page_params[page_param_name][param] = value
99
+
100
+ page_params
101
+ end
102
+
103
+ # @!visibility public
104
+ #
105
+ # Get the pagination request parameters.
106
+ #
107
+ # @param [Symbol] param the request parameter to read pagination
108
+ # options from.
109
+ # @return [Pagination] the pagination state
110
+ def json_pagination( param: :page )
111
+ page_params = params[ param ] || {}
112
+
113
+ Pagination.new( page_params.merge( param: param ) )
114
+ end
115
+
116
+ # @!visibility public
117
+ #
118
+ # Write an error response. See {Shamu::JsonApi::Response#error} for details.
119
+ #
120
+ # @param (see Shamu::JsonApi::Response#error)
121
+ # @yield (builder)
122
+ # @yieldparam [Shamu::JsonApi::ErrorBuilder] builder to customize the
123
+ # error response.
124
+ # @return [JsonApi::Response] the presented JSON response.
125
+ def json_error( error = nil, **context, &block )
126
+ response = build_json_response( context )
127
+
128
+ response.error error do |builder|
129
+ builder.http_status json_http_status_code_from_error( error )
130
+ yield builder if block_given?
131
+ end
132
+
133
+ response.to_json
134
+ end
135
+
136
+ JSON_CONTEXT_KEYWORDS = [ :fields, :namespaces, :presenters ].freeze
137
+
138
+ # @!visibility public
139
+ #
140
+ # Build a {JsonApi::Context} for the current request and controller.
141
+ #
142
+ # @param [Hash<Symbol,Array>] fields to include in the response. If not
143
+ # provided looks for a `fields` request argument and parses that.
144
+ # See {JsonApi::Context#initialize}.
145
+ # @param [Array<String>] namespaces to look for {Presenter presenters}.
146
+ # If not provided automatically adds the controller name and it's
147
+ # namespace.
148
+ #
149
+ # For example in the `Users::AccountController` it will add the
150
+ # `Users::Accounts` and `Users` namespaces.
151
+ #
152
+ # See {JsonApi::Context#find_presenter}.
153
+ # @param [Hash<Class,Class>] presenters a hash that maps resource classes
154
+ # to the presenter class to use when building responses. See
155
+ # {JsonApi::Context#find_presenter}.
156
+ # @return [JsonApi::Context] the builder context honoring any filter
157
+ # parameters sent by the client.
158
+ def json_context( fields: :not_set, namespaces: :not_set, presenters: :not_set )
159
+ Shamu::JsonApi::Context.new fields: fields == :not_set ? json_context_fields : fields,
160
+ namespaces: namespaces == :not_set ? json_context_namespaces : namespaces,
161
+ presenters: presenters == :not_set ? json_context_presenters : presenters
162
+ end
163
+
164
+
165
+ def json_context_fields
166
+ params[:fields]
167
+ end
168
+
169
+ def json_context_namespaces
170
+ name = self.class.name.sub /Controller$/, ""
171
+ namespaces = [ name.pluralize ]
172
+ loop do
173
+ name = name.deconstantize
174
+ break if name.blank?
175
+
176
+ namespaces << name
177
+ end
178
+
179
+ namespaces
180
+ end
181
+
182
+ def json_context_presenters
183
+ end
184
+
185
+ def json_paginate_resources( response, resources, pagination )
186
+ pagination = resources.respond_to?( :current_page ) if pagination == :auto
187
+ return unless pagination
188
+
189
+ json_paginate resources, response
190
+ end
191
+
192
+ def json_http_status_code_from_error( error )
193
+ case error
194
+ when ActiveRecord::RecordNotFound then :not_found
195
+ when ActiveRecord::RecordInvalid then :unprocessable_entity
196
+ when /AccessDenied/ then :forbidden
197
+ else
198
+ if error.is_a?( Exception )
199
+ ActionDispatch::ExceptionWrapper.status_code_for_exception( error )
200
+ else
201
+ :bad_request
202
+ end
203
+ end
204
+ end
205
+
206
+ def json_http_status_code_from_request
207
+ case request.method
208
+ when "POST" then :created
209
+ when "HEAD" then :no_content
210
+ else :ok
211
+ end
212
+ end
213
+
214
+ def build_json_response( context )
215
+ Shamu::JsonApi::Response.new( json_context( **context.slice( *JSON_CONTEXT_KEYWORDS ) ) )
216
+ end
217
+ end
218
+ end
219
+ end
220
+ end
@@ -0,0 +1,54 @@
1
+ module Shamu
2
+ module JsonApi
3
+ module Rails
4
+
5
+ # Pagination information gathered from the request.
6
+ class Pagination
7
+ include Attributes
8
+ include Attributes::Assignment
9
+ include Attributes::Validation
10
+
11
+ # ============================================================================
12
+ # @!group Attributes
13
+ #
14
+
15
+ # @!attribute
16
+ # @return [Symbol] the request parameter the pagination was read from. Default `:page`.
17
+ attribute :param, default: :page
18
+
19
+ # @!attribute
20
+ # @return [Integer] the page number.
21
+ attribute :number, coerce: :to_i
22
+
23
+ # @!attribute
24
+ # @return [Integer] the size of each page.
25
+ attribute :size, coerce: :to_i
26
+
27
+ # @!attribute
28
+ # @return [Integer] offset into the list.
29
+ attribute :offset, coerce: :to_i
30
+
31
+ # @!attribute
32
+ # @return [Integer] limit the total number of results.
33
+ attribute :limit, coerce: :to_i
34
+
35
+ # @!attribute
36
+ # @return [String] opaque cursor value
37
+ attribute :cursor, coerce: :to_i
38
+
39
+ #
40
+ # @!endgroup Attributes
41
+
42
+ validate :only_one_kind_of_paging
43
+
44
+ private
45
+
46
+ def only_one_kind_of_paging
47
+ kinds = [ number, offset, cursor ].compact
48
+ errors.add :base, :only_one_kind_of_paging if kinds.count > 2 || ( size && limit )
49
+ end
50
+
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,55 @@
1
+ module Shamu
2
+ module JsonApi
3
+ module Rails
4
+
5
+ # Support JSON API responses with the standard rails `#respond_with` method.
6
+ module Responder
7
+
8
+ # Render the response as JSON
9
+ # @return [String]
10
+ def to_json
11
+ if has_errors?
12
+ display_errors
13
+ elsif get?
14
+ display resource
15
+ elsif put? || patch?
16
+ display resource, :location => api_location
17
+ elsif post?
18
+ display resource, :status => :created, :location => api_location
19
+ else
20
+ head :no_content
21
+ end
22
+ end
23
+ alias_method :to_json_api, :to_json
24
+
25
+ protected
26
+
27
+ # @visibility private
28
+ def display( resource, given_options = {} )
29
+ given_options.merge!( options )
30
+
31
+ json =
32
+ if resource.is_a?( Enumerable )
33
+ controller.json_collection resource, **given_options
34
+ else
35
+ controller.json_resource resource, **given_options
36
+ end
37
+
38
+ super json, given_options
39
+ end
40
+
41
+ # @visibility private
42
+ def display_errors
43
+ controller.render format => controller.json_validation_errors( resource_errors ), :status => :unprocessable_entity # rubocop:disable Metrics/LineLength
44
+ end
45
+
46
+ private
47
+
48
+ def validation_resource?( resource )
49
+ resource.respond_to?( :valid? ) && resource.respond_to?( :errors )
50
+ end
51
+
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,9 @@
1
+ module Shamu
2
+ module JsonApi
3
+ module Rails
4
+ require "shamu/json_api/rails/controller"
5
+ require "shamu/json_api/rails/responder"
6
+ require "shamu/json_api/rails/pagination"
7
+ end
8
+ end
9
+ end
data/lib/shamu/rails.rb CHANGED
@@ -5,8 +5,7 @@ module Shamu
5
5
  require "shamu/rails/entity"
6
6
  require "shamu/rails/controller"
7
7
  require "shamu/rails/features"
8
- require "shamu/rails/json_api"
9
- require "shamu/rails/json_api_responder"
10
8
  require "shamu/rails/railtie"
9
+ require "shamu/json_api/rails"
11
10
  end
12
11
  end
data/lib/shamu/version.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
  module Shamu
3
3
  # The primary version number
4
- VERSION_NUMBER = "0.0.7".freeze
4
+ VERSION_NUMBER = "0.0.8".freeze
5
5
 
6
6
  # Version suffix such as 'beta' or 'alpha'
7
7
  VERSION_SUFFIX = "".freeze
@@ -8,7 +8,7 @@ module JsonApiControllerSpec
8
8
  end
9
9
 
10
10
  class ResourcesController < ActionController::Base
11
- include Shamu::Rails::JsonApi
11
+ include Shamu::JsonApi::Rails::Controller
12
12
  end
13
13
 
14
14
  module Resources
@@ -78,12 +78,21 @@ describe JsonApiControllerSpec::ResourcesController, type: :controller do
78
78
  end
79
79
 
80
80
  subject do
81
- get :index, format: :json
81
+ get :index
82
82
  JSON.parse( response.body )
83
83
  end
84
84
 
85
85
  it { is_expected.to include "data" => kind_of( Array ) }
86
- it { is_expected.to include "links" => hash_including( "next" ) }
86
+ it { is_expected.to include "links" => include( "next" => match( /page.*number/ ) ) }
87
+ end
88
+
89
+ describe "#json_pagination" do
90
+ it "parses pagination parameters" do
91
+ controller.params[:page] = { number: 3 }
92
+ pagination = controller.send :json_pagination
93
+
94
+ expect( pagination.number ).to eq 3
95
+ end
87
96
  end
88
97
 
89
98
  it "writes an error" do
@@ -0,0 +1,11 @@
1
+ require "rails_helper"
2
+
3
+ describe Shamu::JsonApi::Rails::Pagination do
4
+ it "retains nil value if not set" do
5
+ expect( Shamu::JsonApi::Rails::Pagination.new.number ).to be_nil
6
+ end
7
+
8
+ it "only allows one kind of paging" do
9
+ expect( Shamu::JsonApi::Rails::Pagination.new( size: 1, limit: 1 ) ).not_to be_valid
10
+ end
11
+ end
@@ -8,13 +8,13 @@ module JsonApiResponderSpec
8
8
  end
9
9
 
10
10
  class Responder < ActionController::Responder
11
- include Shamu::Rails::JsonApiResponder
11
+ include Shamu::JsonApi::Rails::Responder
12
12
  end
13
13
 
14
14
  class ResourcesController < ActionController::Base
15
- include Shamu::Rails::JsonApi
15
+ include Shamu::JsonApi::Rails::Controller
16
16
 
17
- respond_to :json, :json_api
17
+ respond_to :json_api, :json
18
18
  self.responder = Responder
19
19
 
20
20
  def json_api_responder_spec_resource_url( * )
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shamu
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.7
4
+ version: 0.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul Alexander
@@ -286,6 +286,10 @@ files:
286
286
  - lib/shamu/json_api/error.rb
287
287
  - lib/shamu/json_api/error_builder.rb
288
288
  - lib/shamu/json_api/presenter.rb
289
+ - lib/shamu/json_api/rails.rb
290
+ - lib/shamu/json_api/rails/controller.rb
291
+ - lib/shamu/json_api/rails/pagination.rb
292
+ - lib/shamu/json_api/rails/responder.rb
289
293
  - lib/shamu/json_api/relationship_builder.rb
290
294
  - lib/shamu/json_api/resource_builder.rb
291
295
  - lib/shamu/json_api/response.rb
@@ -301,8 +305,6 @@ files:
301
305
  - lib/shamu/rails/controller.rb
302
306
  - lib/shamu/rails/entity.rb
303
307
  - lib/shamu/rails/features.rb
304
- - lib/shamu/rails/json_api.rb
305
- - lib/shamu/rails/json_api_responder.rb
306
308
  - lib/shamu/rails/railtie.rb
307
309
  - lib/shamu/rspec.rb
308
310
  - lib/shamu/rspec/matchers.rb
@@ -389,6 +391,9 @@ files:
389
391
  - spec/lib/shamu/json_api/common_builder_spec.rb
390
392
  - spec/lib/shamu/json_api/context_spec.rb
391
393
  - spec/lib/shamu/json_api/error_builder_spec.rb
394
+ - spec/lib/shamu/json_api/rails/controller_spec.rb
395
+ - spec/lib/shamu/json_api/rails/pagination_spec.rb
396
+ - spec/lib/shamu/json_api/rails/responder_spec.rb
392
397
  - spec/lib/shamu/json_api/relationship_builder_spec.rb
393
398
  - spec/lib/shamu/json_api/resource_builder_spec.rb
394
399
  - spec/lib/shamu/json_api/response_spec.rb
@@ -400,8 +405,6 @@ files:
400
405
  - spec/lib/shamu/rails/entity_spec.rb
401
406
  - spec/lib/shamu/rails/features.yml
402
407
  - spec/lib/shamu/rails/features_spec.rb
403
- - spec/lib/shamu/rails/json_api_responder_spec.rb
404
- - spec/lib/shamu/rails/json_api_spec.rb
405
408
  - spec/lib/shamu/security/active_record_policy_spec.rb
406
409
  - spec/lib/shamu/security/hashed_value_spec.rb
407
410
  - spec/lib/shamu/security/policy_refinement_spec.rb
@@ -501,6 +504,9 @@ test_files:
501
504
  - spec/lib/shamu/json_api/common_builder_spec.rb
502
505
  - spec/lib/shamu/json_api/context_spec.rb
503
506
  - spec/lib/shamu/json_api/error_builder_spec.rb
507
+ - spec/lib/shamu/json_api/rails/controller_spec.rb
508
+ - spec/lib/shamu/json_api/rails/pagination_spec.rb
509
+ - spec/lib/shamu/json_api/rails/responder_spec.rb
504
510
  - spec/lib/shamu/json_api/relationship_builder_spec.rb
505
511
  - spec/lib/shamu/json_api/resource_builder_spec.rb
506
512
  - spec/lib/shamu/json_api/response_spec.rb
@@ -512,8 +518,6 @@ test_files:
512
518
  - spec/lib/shamu/rails/entity_spec.rb
513
519
  - spec/lib/shamu/rails/features.yml
514
520
  - spec/lib/shamu/rails/features_spec.rb
515
- - spec/lib/shamu/rails/json_api_responder_spec.rb
516
- - spec/lib/shamu/rails/json_api_spec.rb
517
521
  - spec/lib/shamu/security/active_record_policy_spec.rb
518
522
  - spec/lib/shamu/security/hashed_value_spec.rb
519
523
  - spec/lib/shamu/security/policy_refinement_spec.rb
@@ -1,192 +0,0 @@
1
- require "rack"
2
-
3
- module Shamu
4
- module Rails
5
-
6
- # Add support for writing resources as well-formed JSON API.
7
- module JsonApi
8
- extend ActiveSupport::Concern
9
-
10
- included do
11
- before_action do
12
- render json: json_error( "The 'include' parameter is not supported" ), status: :bad_request if params[:include] # rubocop:disable Metrics/LineLength
13
- end
14
- end
15
-
16
- def process_action( * )
17
- # If no format has been specfied, default to json_api
18
- request.parameters[:format] ||= "json_api"
19
- super
20
- end
21
-
22
- # Builds a well-formed JSON API response for a single resource.
23
- #
24
- # @param [Object] resource to present as JSON.
25
- # @param [Class] presenter {Presenter} class to use when building the
26
- # response for the given resource. If not given, attempts to find a
27
- # presenter by calling {Context#find_presenter}.
28
- # @param (see #json_context)
29
- # @yield (response) write additional top-level links and meta
30
- # information.
31
- # @yieldparam [JsonApi::Response] response
32
- # @return [JsonApi::Response] the presented JSON response.
33
- def json_resource( resource, presenter = nil, **context, &block )
34
- response = build_json_response( context )
35
- response.resource resource, presenter
36
- yield response if block_given?
37
- response.to_json
38
- end
39
-
40
- # Builds a well-formed JSON API response for a collection of resources.
41
- #
42
- # @param [Enumerable<Object>] resources to present as a JSON array.
43
- # @param [Class] presenter {Presenter} class to use when building the
44
- # response for each of the resources. If not given, attempts to find
45
- # a presenter by calling {Context#find_presenter}
46
- # @param (see #json_context)
47
- # @yield (response) write additional top-level links and meta
48
- # information.
49
- # @yieldparam [JsonApi::Response] response
50
- # @return [JsonApi::Response] the presented JSON response.
51
- def json_collection( resources, presenter = nil, pagination: :auto, **context, &block )
52
- response = build_json_response( context )
53
- response.collection resources, presenter
54
- json_paginate_resources response, resources, pagination
55
- yield response if block_given?
56
- response.to_json
57
- end
58
-
59
- # Add page-based pagination links for the resources to the builder.
60
- #
61
- # @param [#current_page,#next_page,#previous_page] resources a collection that responds to `#current_page`
62
- # @param [JsonApi::BaseBuilder] builder to add links to.
63
- # @param [String] param the name of the page parameter to adjust for
64
- # @return [void]
65
- def json_paginate( resources, builder, param: "page[number]" )
66
- page = resources.current_page
67
-
68
- if resources.respond_to?( :next_page ) ? resources.next_page : true
69
- builder.link :next, url_for( params.reverse_merge( param => resources.current_page + 1 ) )
70
- end
71
-
72
- if resources.respond_to?( :prev_page ) ? resources.prev_page : page > 1
73
- builder.link :prev, url_for( params.reverse_merge( param => resources.current_page - 1 ) )
74
- end
75
- end
76
-
77
- # Write an error response. See {Shamu::JsonApi::Response#error} for details.
78
- #
79
- # @param (see Shamu::JsonApi::Response#error)
80
- # @yield (builder)
81
- # @yieldparam [Shamu::JsonApi::ErrorBuilder] builder to customize the
82
- # error response.
83
- # @return [JsonApi::Response] the presented JSON response.
84
- def json_error( error = nil, **context, &block )
85
- response = build_json_response( context )
86
-
87
- response.error error do |builder|
88
- builder.http_status json_http_status_code_from_error( error )
89
- yield builder if block_given?
90
- end
91
-
92
- response.to_json
93
- end
94
-
95
- # Write all the validation errors from a record to the response.
96
- #
97
- # @param (see Shamu::JsonApi::Response#validation_errors)
98
- # @yield (builder, attr, message)
99
- # @yieldparam (see Shamu::JsonApi::Response#validation_errors)
100
- # @return [JsonApi::Response] the presented JSON response.
101
- def json_validation_errors( errors, **context, &block )
102
- response = build_json_response( context )
103
- response.validation_errors errors, &block
104
-
105
- response.to_json
106
- end
107
-
108
- JSON_CONTEXT_KEYWORDS = [ :fields, :namespaces, :presenters ].freeze
109
-
110
- # @!visibility public
111
- #
112
- # Build a {JsonApi::Context} for the current request and controller.
113
- #
114
- # @param [Hash<Symbol,Array>] fields to include in the response. If not
115
- # provided looks for a `fields` request argument and parses that.
116
- # See {JsonApi::Context#initialize}.
117
- # @param [Array<String>] namespaces to look for {Presenter presenters}.
118
- # If not provided automatically adds the controller name and it's
119
- # namespace.
120
- #
121
- # For example in the `Users::AccountController` it will add the
122
- # `Users::Accounts` and `Users` namespaces.
123
- #
124
- # See {JsonApi::Context#find_presenter}.
125
- # @param [Hash<Class,Class>] presenters a hash that maps resource classes
126
- # to the presenter class to use when building responses. See
127
- # {JsonApi::Context#find_presenter}.
128
- # @return [JsonApi::Context] the builder context honoring any filter
129
- # parameters sent by the client.
130
- def json_context( fields: :not_set, namespaces: :not_set, presenters: :not_set )
131
- Shamu::JsonApi::Context.new fields: fields == :not_set ? json_context_fields : fields,
132
- namespaces: namespaces == :not_set ? json_context_namespaces : namespaces,
133
- presenters: presenters == :not_set ? json_context_presenters : presenters
134
- end
135
-
136
- private
137
-
138
- def json_context_fields
139
- params[:fields]
140
- end
141
-
142
- def json_context_namespaces
143
- name = self.class.name.sub /Controller$/, ""
144
- namespaces = [ name.pluralize ]
145
- loop do
146
- name = name.deconstantize
147
- break if name.blank?
148
-
149
- namespaces << name
150
- end
151
-
152
- namespaces
153
- end
154
-
155
- def json_context_presenters
156
- end
157
-
158
- def json_paginate_resources( response, resources, pagination )
159
- pagination = resources.respond_to?( :current_page ) if pagination == :auto
160
- return unless pagination
161
-
162
- json_paginate resources, response
163
- end
164
-
165
- def json_http_status_code_from_error( error )
166
- case error
167
- when ActiveRecord::RecordNotFound then :not_found
168
- when ActiveRecord::RecordInvalid then :unprocessable_entity
169
- when /AccessDenied/ then :forbidden
170
- else
171
- if error.is_a?( Exception )
172
- ActionDispatch::ExceptionWrapper.status_code_for_exception( error )
173
- else
174
- :bad_request
175
- end
176
- end
177
- end
178
-
179
- def json_http_status_code_from_request
180
- case request.method
181
- when "POST" then :created
182
- when "HEAD" then :no_content
183
- else :ok
184
- end
185
- end
186
-
187
- def build_json_response( context )
188
- Shamu::JsonApi::Response.new( json_context( **context.slice( *JSON_CONTEXT_KEYWORDS ) ) )
189
- end
190
- end
191
- end
192
- end
@@ -1,53 +0,0 @@
1
- module Shamu
2
- module Rails
3
-
4
- # Support JSON API responses with the standard rails `#respond_with` method.
5
- module JsonApiResponder
6
-
7
- # Render the response as JSON
8
- # @return [String]
9
- def to_json
10
- if has_errors?
11
- display_errors
12
- elsif get?
13
- display resource
14
- elsif put? || patch?
15
- display resource, :location => api_location
16
- elsif post?
17
- display resource, :status => :created, :location => api_location
18
- else
19
- head :no_content
20
- end
21
- end
22
- alias_method :to_json_api, :to_json
23
-
24
- protected
25
-
26
- # @visibility private
27
- def display( resource, given_options = {} )
28
- given_options.merge!( options )
29
-
30
- json =
31
- if resource.is_a?( Enumerable )
32
- controller.json_collection resource, **given_options
33
- else
34
- controller.json_resource resource, **given_options
35
- end
36
-
37
- super json, given_options
38
- end
39
-
40
- # @visibility private
41
- def display_errors
42
- controller.render format => controller.json_validation_errors( resource_errors ), :status => :unprocessable_entity # rubocop:disable Metrics/LineLength
43
- end
44
-
45
- private
46
-
47
- def validation_resource?( resource )
48
- resource.respond_to?( :valid? ) && resource.respond_to?( :errors )
49
- end
50
-
51
- end
52
- end
53
- end