Install JSONAPI.rb
masterTo use JSONAPI.rb in your Ruby application, add the gem to your Gemfile and run bundle:
gem 'jsonapi.rb'Alternatively, you can install it directly via the command line:
$ gem install jsonapi.rbrepository·master·Indexed 42 days ago
https://github.com/stas/jsonapi.rbA collection of Ruby modules and mixins for Rails developers to implement the JSON:API specification with minimal boilerplate. It provides tools for serialization, deserialization, pagination, filtering via Ransack, and automated error handling for ActiveRecord and ActionController exceptions.
To use JSONAPI.rb in your Ruby application, add the gem to your Gemfile and run bundle:
gem 'jsonapi.rb'Alternatively, you can install it directly via the command line:
$ gem install jsonapi.rbTo integrate JSONAPI.rb with Rails, you must register the appropriate mime types and renderers (jsonapi and jsonapi_errors) by adding an initializer:
# config/initializers/jsonapi.rb
require 'jsonapi'
JSONAPI::Rails.install!JSONAPI.rb provides filtering and sorting support that leverages Ransack specifications. This allows you to pass complex query parameters via the URL to filter and order ActiveRecord collections.
filter parameter. Fields can include predicates (e.g., matches_any).sort parameter. Prefix a field with - for descending order, otherwise it defaults to ascending.GET /resource?filter[region_matches_any]=Lisb%&sort=-created_at,id
By default, JSONAPI::Rails resolves a serializer class by appending Serializer to the class name of the resource (e.g., User becomes UserSerializer).
If you need to override this behavior, you can define a jsonapi_serializer_class method in your controller. The renderer checks for this method before falling back to the default JSONAPI::Rails.serializer_class logic.
The ErrorSerializer automatically overrides serializable_hash to ensure the JSON:API response uses the errors root key. It maps the contents of the :data array to the :attributes of each error object in the resulting hash.
Expected output structure:
{
"errors": [
{ "status": "422", "detail": "Invalid attribute" }
]
}To integrate JSONAPI.rb with a Rails application, call JSONAPI::Rails.install!. This method performs the following setup:
:jsonapi MIME type.jsonapi requests (ensuring params are parsed correctly for JSONAPI content-type).:jsonapi renderer to ActionController.:jsonapi_errors renderer to ActionController.Note: This method checks if ::Rails is defined before proceeding.
# In a Rails initializer (e.g., config/initializers/jsonapi.rb)
JSONAPI::Rails.install!Include the JSONAPI::Errors module in your Rails controllers to automatically catch common exceptions and render them as compliant JSON:API error responses.
When included, the module uses rescue_from to register handlers for:
StandardError: Renders a 500 Internal Server Error.ActiveRecord::RecordNotFound: Renders a 404 Not Found (if ActiveRecord is defined).ActionController::ParameterMissing: Renders a 422 Unprocessable Entity (if ActionController is defined).Note: In Rails test environments, StandardError handling is skipped to allow standard test exception reporting.
class ApplicationController < ActionController::Base
include JSONAPI::Errors
endInclude JSONAPI::Errors to automatically handle exceptions from strong parameters, generic errors, or record-not-found errors. To render validation errors, use the jsonapi_errors renderer.
To integrate an exception notifier (like Raven), override render_jsonapi_internal_server_error(exception):
class MyController < ActionController::Base
include JSONAPI::Errors
def update
record = Model.find(params[:id])
if record.update(params.require(:data).require(:attributes).permit!)
render jsonapi: record
else
render jsonapi_errors: record.errors, status: :unprocessable_entity
end
end
private
def render_jsonapi_internal_server_error(exception)
# Call your exception notifier here. Example:
# Raven.capture_exception(exception)
super(exception)
end
endTo include metadata (like total counts) in your JSON:API collection responses, implement the jsonapi_meta(resources) method in your controller:
class MyController < ActionController::Base
def index
render jsonapi: Model.all
end
private
def jsonapi_meta(resources)
{ total: resources.count } if resources.respond_to?(:count)
end
endThe JSONAPI::Filtering module uses Ransack to provide filtering and sorting capabilities. Note: You must add ransack to your Gemfile to use this.
Implement jsonapi_filter in your controller:
class MyController < ActionController::Base
include JSONAPI::Filtering
def index
allowed = [:model_attr, :relationship_attr]
jsonapi_filter(Model.all, allowed) do |filtered|
render jsonapi: filtered.result
end
end
endThis supports queries like:
curl -X GET /api/resources?filter[model_attr_or_relationship_attr_cont_any]=value,name&sort=-model_attr,relationship_attr
To use SQL aggregations (e.g., min, max, avg, sum, count) for sorting, enable the sort_with_expressions option:
options = { sort_with_expressions: true }
jsonapi_filter(User.all, allowed_fields, options) do |filtered|
render jsonapi: filtered.result.group('id').to_a
endThis enables queries like:
curl -X GET /api/resources?sort=-model_attr_sum
The jsonapi_deserialize helper transforms a JSON:API document into a flat dictionary suitable for updating an ActiveRecord::Base model.
class MyController < ActionController::Base
include JSONAPI::Deserialization
def update
model = MyModel.find(params[:id])
if model.update(jsonapi_deserialize(params, only: [:attr1, :rel_one]))
render jsonapi: model
else
render jsonapi_errors: model.errors, status: :unprocessable_entity
end
end
endonly: Returns exclusively attributes/relationship data in the provided list.except: Returns exclusively attributes/relationship NOT in the provided list.polymorphic: Adds and detects the _type attribute and class for defined polymorphic relationships.Note: This requires inflections. If you are not using Rails/ActiveSupport, ensure you have the dry/inflector gem installed.
Include JSONAPI::Pagination to support paginating model record sets. This automatically generates relevant pagination _links.
class MyController < ActionController::Base
include JSONAPI::Pagination
def index
jsonapi_paginate(Model.all) do |paginated|
render jsonapi: paginated
end
end
endTo add pagination info to your collection's meta, use jsonapi_pagination_meta inside your jsonapi_meta method:
def jsonapi_meta(resources)
pagination = jsonapi_pagination_meta(resources)
{ pagination: pagination } if pagination.present?
endTo change the default items per page or implement custom logic, implement jsonapi_page_size(pagination_params):
def jsonapi_page_size(pagination_params)
per_page = pagination_params[:size].to_f.to_i
per_page = 30 if per_page > 30 || per_page < 1
per_page
end