lib/shamu/rails/json_api.rb in shamu-0.0.4 vs lib/shamu/rails/json_api.rb in shamu-0.0.5
- old
+ new
@@ -7,165 +7,136 @@
module JsonApi
extend ActiveSupport::Concern
included do
before_action do
- json_api error: "The 'include' parameter is not supported", status: :bad_request if params[:include]
+ render json: json_error( "The 'include' parameter is not supported" ), status: :bad_request if params[:include] # rubocop:disable Metrics/LineLength
end
end
- private
+ def process_action( * )
+ # If no format has been specfied, default to json_api
+ request.parameters[:format] ||= "json_api"
+ super
+ end
- # @!visibility public
- #
- # Writes a single resource as a well-formed JSON API response.
- #
- # @param [Object] resource to present as JSON.
- # @param [JsonApi::Presenter] presenter to use when building the
- # response. If not given, attempts to find a presenter. See
- # {#json_context}
- # @param (see #json_context)
- # @yield (response) write additional top-level links and meta
- # information.
- # @yieldparam [JsonApi::Response] response
- # @return [JsonApi::Response] the presented json response.
- def json_resource( resource, presenter = nil, **context, &block )
- context = json_context( **context )
- response = Shamu::JsonApi::Response.new( context )
- response.resource resource, presenter
- yield response if block_given?
- response
- end
+ # Builds a well-formed JSON API response for a single resource.
+ #
+ # @param [Object] resource to present as JSON.
+ # @param [Class] presenter {Presenter} class to use when building the
+ # response for the given resource. If not given, attempts to find a
+ # presenter by calling {Context#find_presenter}.
+ # @param (see #json_context)
+ # @yield (response) write additional top-level links and meta
+ # information.
+ # @yieldparam [JsonApi::Response] response
+ # @return [JsonApi::Response] the presented JSON response.
+ def json_resource( resource, presenter = nil, **context, &block )
+ response = build_json_response( context )
+ response.resource resource, presenter
+ yield response if block_given?
+ response
+ end
- # @!visibility public
- #
- # Writes a single resource as a well-formed JSON API response.
- #
- # @param [Enumerabl<Object>] resources to present as a JSON array.
- # @param [JsonApi::Presenter] presenter to use when building the
- # response. If not given, attempts to find a presenter. See
- # {#json_context}
- # @param (see #json_context)
- # @yield (response) write additional top-level links and meta
- # information.
- # @yieldparam [JsonApi::Response] response
- # @return [JsonApi::Response] the presented json response.
- def json_collection( resources, presenter = nil, pagination: :auto, **context, &block )
- context = json_context( **context )
- response = Shamu::JsonApi::Response.new( context )
- response.collection resources, presenter
- json_paginate_resources response, resources, pagination
- yield response if block_given?
- response
- end
+ # Builds a well-formed JSON API response for a collection of resources.
+ #
+ # @param [Enumerable<Object>] resources to present as a JSON array.
+ # @param [Class] presenter {Presenter} class to use when building the
+ # response for each of the resources. If not given, attempts to find
+ # a presenter by calling {Context#find_presenter}
+ # @param (see #json_context)
+ # @yield (response) write additional top-level links and meta
+ # information.
+ # @yieldparam [JsonApi::Response] response
+ # @return [JsonApi::Response] the presented JSON response.
+ def json_collection( resources, presenter = nil, pagination: :auto, **context, &block )
+ response = build_json_response( context )
+ response.collection resources, presenter
+ json_paginate_resources response, resources, pagination
+ yield response if block_given?
+ response
+ end
- # @!visibility public
- #
- # Add page-based pagination links for the resources.
- #
- # @param [#current_page,#next_page,#previous_page] resources a collection that responds to `#current_page`
- # @param [JsonApi::BaseBuilder] builder to add links to.
- # @param [String] param the name of the page parameter to adjust for
- def json_paginate( resources, builder, param: "page[number]" )
- page = resources.current_page
+ # Add page-based pagination links for the resources to the builder.
+ #
+ # @param [#current_page,#next_page,#previous_page] resources a collection that responds to `#current_page`
+ # @param [JsonApi::BaseBuilder] builder to add links to.
+ # @param [String] param the name of the page parameter to adjust for
+ # @return [void]
+ def json_paginate( resources, builder, param: "page[number]" )
+ page = resources.current_page
- if resources.respond_to?( :next_page ) ? resources.next_page : true
- builder.link :next, url_for( params.reverse_merge( param => resources.current_page + 1 ) )
- end
+ if resources.respond_to?( :next_page ) ? resources.next_page : true
+ builder.link :next, url_for( params.reverse_merge( param => resources.current_page + 1 ) )
+ end
- if resources.respond_to?( :prev_page ) ? resources.prev_page : page > 1
- builder.link :prev, url_for( params.reverse_merge( param => resources.current_page - 1 ) )
- end
+ if resources.respond_to?( :prev_page ) ? resources.prev_page : page > 1
+ builder.link :prev, url_for( params.reverse_merge( param => resources.current_page - 1 ) )
end
+ end
- # @!visiblity public
- #
- # Write an error response. See {Shamu::JsonApi::Response#error} for details.
- #
- # @param (see Shamu::JsonApi::Response#error)
- # @return [Shamu::JsonApi::Response]
- # @yield (builder)
- # @yieldparam [Shamu::JsonApi::ErrorBuilder] builder to customize the
- # error response.
- def json_error( exception = nil, http_status = :auto, **context, &block )
- context = json_context( **context )
- response = Shamu::JsonApi::Response.new( context )
+ # Write an error response. See {Shamu::JsonApi::Response#error} for details.
+ #
+ # @param (see Shamu::JsonApi::Response#error)
+ # @yield (builder)
+ # @yieldparam [Shamu::JsonApi::ErrorBuilder] builder to customize the
+ # error response.
+ # @return [JsonApi::Response] the presented JSON response.
+ def json_error( error = nil, **context, &block )
+ response = build_json_response( context )
- http_status = json_http_status_code_from_error( exception ) if http_status == :auto
- http_status = ::Rack::Utils.status_code( http_status ) if http_status
- response.error( exception, http_status, &block )
- response
+ response.error error do |builder|
+ builder.http_status json_http_status_code_from_error( error )
+ yield builder if block_given?
end
- # @!visibility public
- #
- # Buid a {JsonApi::Context} for the current request and controller.
- #
- # @param [Hash<Symbol,Array>] fields to include in the response. If not
- # provided looks for a `fields` request argument and parses that.
- # See {JsonApi::Context#initialize}.
- # @param [Array<String>] namespaces to look for {Presenter presenters}.
- # If not provided automatically adds the controller name and it's
- # namespace.
- #
- # For example in the `Users::AccountController` it will add the
- # `Users::Accounts` and `Users` namespaces.
- #
- # See {JsonApi::Context#find_presenter}.
- # @param [Hash<Class,Class>] presenters a hash that maps resource classes
- # to the presenter class to use when building responses. See
- # {JsonApi::Context#find_presenter}.
- def json_context( fields: :not_set, namespaces: :not_set, presenters: :not_set )
- Shamu::JsonApi::Context.new fields: fields == :not_set ? json_context_fields : fields,
- namespaces: namespaces == :not_set ? json_context_namespaces : namespaces,
- presenters: presenters == :not_set ? json_context_presenters : presenters
- end
+ response
+ end
- # rubocop:disable Metrics/PerceivedComplexity
+ # Write all the validation errors from a record to the response.
+ #
+ # @param (see Shamu::JsonApi::Response#validation_errors)
+ # @yield (builder, attr, message)
+ # @yieldparam (see Shamu::JsonApi::Response#validation_errors)
+ # @return [JsonApi::Response] the presented JSON response.
+ def json_validation_errors( errors, **context, &block )
+ response = build_json_response( context )
+ response.validation_errors errors, &block
- # @!visibility public
- #
- # Render a JSON API response for a resource, collection or error.
- #
- # @overload json_api( error:, status: :auto, **context, &block )
- # @param [Exception] error an error to report
- # @param [Symbol,Integer] status the HTTP status code to return. If
- # :auto, attempts to determine the proper response from the
- # exception and request type.
- # @param (see #json_context)
- # @overload json_api( resource:, status: :auto, presenter: nil, **context, &block )
- # @param [Object] resource the resource to render.
- # @param [Symbol,Integer] status the HTTP status code. If :auto
- # attempts to determine the proper response from the request type.
- # @param (see #json_resource)
- # @param [Shamu::JsonApi::Presenter] presenter to use when serializing
- # the resource.
- # @overload json_api( collection:, status: :ok, presenter: nil, **context, &block )
- # @param [Array<Object>] collection to render.
- # @param [Symbol,Integer] statis HTTP status code.
- # @param (see #json_collection)
- # @param [Shamu::JsonApi::Presenter] presenter to use when serializing
- # each of the resources.
- def json_api( error: nil, resource: nil, collection: nil, status: :auto, presenter: nil, pagination: :auto, **context, &block ) # rubocop:disable Metrics/LineLength
- options = { layout: nil }
+ response
+ end
- options[:json] =
- if error
- status = json_http_status_code_from_error( error ) if status == :auto
- json_error( error, status, **context, &block )
- elsif collection
- status = :ok if status == :auto
- json_collection( collection, presenter, pagination: pagination, **context, &block )
- else
- status = json_http_status_code_from_request if status == :auto
- json_resource( resource, presenter, **context, &block )
- end
+ JSON_CONTEXT_KEYWORDS = [ :fields, :namespaces, :presenters ].freeze
- options[:status] = status if status
- render options.merge( context.except( :fields, :namespaces, :presenters ) )
- end
+ # @!visibility public
+ #
+ # Build a {JsonApi::Context} for the current request and controller.
+ #
+ # @param [Hash<Symbol,Array>] fields to include in the response. If not
+ # provided looks for a `fields` request argument and parses that.
+ # See {JsonApi::Context#initialize}.
+ # @param [Array<String>] namespaces to look for {Presenter presenters}.
+ # If not provided automatically adds the controller name and it's
+ # namespace.
+ #
+ # For example in the `Users::AccountController` it will add the
+ # `Users::Accounts` and `Users` namespaces.
+ #
+ # See {JsonApi::Context#find_presenter}.
+ # @param [Hash<Class,Class>] presenters a hash that maps resource classes
+ # to the presenter class to use when building responses. See
+ # {JsonApi::Context#find_presenter}.
+ # @return [JsonApi::Context] the builder context honoring any filter
+ # parameters sent by the client.
+ def json_context( fields: :not_set, namespaces: :not_set, presenters: :not_set )
+ Shamu::JsonApi::Context.new fields: fields == :not_set ? json_context_fields : fields,
+ namespaces: namespaces == :not_set ? json_context_namespaces : namespaces,
+ presenters: presenters == :not_set ? json_context_presenters : presenters
+ end
+ private
+
def json_context_fields
params[:fields]
end
def json_context_namespaces
@@ -209,9 +180,13 @@
case request.method
when "POST" then :created
when "HEAD" then :no_content
else :ok
end
+ end
+
+ def build_json_response( context )
+ Shamu::JsonApi::Response.new( json_context( **context.slice( *JSON_CONTEXT_KEYWORDS ) ) )
end
end
end
end
\ No newline at end of file