Preconfigured set of libraries for building JSON:API compliant endpoints, with matchers for writing more declarative JSON:API specs. This library presumes host project is compliant with using
- rails as an application server
- jsonapi_parameters for incoming data parsing
- json_schemer for validating JSON structures
- responders for writing declarative actions
- Add Infinum JSON:API setup to your Gemfile
gem 'infinum_json_api_setup'- Next, run the generator
bundle exec rails generate infinum_json_api_setup:installThe generator will copy the default translations into the host project (config/locales/json_api.en.yml), where they can be customized.
Create abstract class for your controllers, include common JSON:API request processing behaviour, and configure responders.
module Api
class BaseController < ActionController::API
include InfinumJsonApiSetup::JsonApi::ErrorHandling
include InfinumJsonApiSetup::JsonApi::ContentNegotiation
include InfinumJsonApiSetup::JsonApi::LocaleNegotiation
self.responder = InfinumJsonApiSetup::JsonApi::Responder
respond_to :json_api
end
endUse jsonapi_parameters to transform incoming JSON:API compliant data into common Rails parameters
def permitted_params
params.from_jsonapi
.require(:user)
.permit(:first_name, :last_name)
endUse respond_with to initiate transformation (serialization) of domain objects into HTTP response.
def show
respond_with User.find(params[:id])
endrespond_with is well integrated with ActiveRecord::Model interface. Given a compliant object, the method will correctly set a response status and handle object(or error) serialization based on the presence of .errors. For a successful domain operation, HTTP status will be 200 OK (or 201 in case of create controller action). Unsuccessful operations will have HTTP status 422 Unprocessable Entity with errors structured according to JSON:API specification.
def create
respond_with User.create(permitted_params)
endrespond_with also detects usage from a destroy controller action and responds with HTTP status 204 No Content and an empty body.
def destroy
respond_with User.destroy(params[:id])
endThis section explains the under-the-hood behavior of the library.
InfinumJsonApiSetup::JsonApi::ContentNegotiation module is designed to integrate server responsibilities of content negotiation protocol described by the JSON:API specification.
InfinumJsonApiSetup::JsonApi::LocaleNegotiation module ensures that request handling happens within the locale best matching the Accept-Language header.
- Default behavior: locale falls back to the application's default when the header is missing.
- Invalid locales: enable graceful fallback by setting
self.fallback_to_default_locale_if_invalid = truein your controller when you want to disregard unrecognized locales instead of raisingjson_api.errors.bad_request.invalid_locale. - Error handling: when fallback is disabled (default), requests with invalid locales trigger a JSON:API formatted bad request response.
InfinumJsonApiSetup::JsonApi::ErrorHandling module is designed to catch and handle common exceptions that might bubble up when processing a request.
| Exception | HTTP status | Bugsnag notification |
|---|---|---|
ActionController::ParameterMissing |
400 | |
ActionDispatch::Http::Parameters::ParseError |
400 | |
Jure::UnpermittedSortParameters |
400 | ✅ |
I18n::InvalidLocale |
400 | |
Pundit::NotAuthorizedError |
403 | ✅ |
ActiveRecord::RecordNotFound |
404 | |
PG::Error |
500 |
InfinumJsonApiSetup::JsonApi::ErrorSerializer is responsible for serializing domain errors according to JSON:API specification.
Library ships with a set of declarative matchers and request/response helpers. To use them in your specs, configure your RSpec setup in the following way which
- includes all defined matchers
- includes request and response helper methods into specs tagged with
:requestmetadata - configures search paths for resolving JSON schema files
require 'infinum_json_api_setup/rspec'
RSpec.configure do |config|
# Helpers
config.include InfinumJsonApiSetup::Rspec::Helpers::RequestHelper, type: :request
config.include InfinumJsonApiSetup::Rspec::Helpers::ResponseHelper, type: :request
# Schema paths
config.schema_response_root = Rails.application.root.join('path/to/response_schemas')
config.schema_request_root = Rails.application.root.join('path/to/request_schemas')
endexpect(response).to have_empty_dataexpect(response).to have_error_pointer('data/attributes/first_name')expect(response).to have_resource_count_of(3)expect(response).to include_all_resource_ids(records.map(&:id))expect(response).to include_all_resource_ids_sorted(records.map(&:id))expect(response).to include_all_resource_string_ids(records.map(&:id).map(&:to_s))expect(response).to include_error_detail('name has been taken')expect(response).to include_related_resource('user', user.id)JSON:API setup is maintained and sponsored by Infinum
The gem is available as open source under the terms of the MIT License.