Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/stas/jsonapi.rb
Lightweight, simple and maintained JSON:API support for your next Ruby HTTP API.
https://github.com/stas/jsonapi.rb
api arel error-handling fast-jsonapi filter json-api jsonapi pagination rails ransack serializer
Last synced: about 2 months ago
JSON representation
Lightweight, simple and maintained JSON:API support for your next Ruby HTTP API.
- Host: GitHub
- URL: https://github.com/stas/jsonapi.rb
- Owner: stas
- License: mit
- Created: 2019-01-11T19:12:08.000Z (over 5 years ago)
- Default Branch: master
- Last Pushed: 2024-06-23T13:35:50.000Z (3 months ago)
- Last Synced: 2024-07-26T08:21:06.707Z (about 2 months ago)
- Topics: api, arel, error-handling, fast-jsonapi, filter, json-api, jsonapi, pagination, rails, ransack, serializer
- Language: Ruby
- Homepage:
- Size: 190 KB
- Stars: 260
- Watchers: 8
- Forks: 57
- Open Issues: 12
-
Metadata Files:
- Readme: README.md
- License: LICENSE.txt
Awesome Lists containing this project
README
# JSONAPI.rb :electric_plug:
[![Build Status](https://travis-ci.org/stas/jsonapi.rb.svg?branch=master)](https://travis-ci.org/stas/jsonapi.rb)
So you say you need [JSON:API](https://jsonapi.org/) support in your API...
> - hey how did your hackathon go?
> - not too bad, we got Babel set up
> - yep…
> - yep.
>
>— [I Am Devloper](https://twitter.com/iamdevloper/status/787969734918668289)Here are some _codes_ to help you build your next JSON:API compliable application
easier and faster.## But why?
It's quite a hassle to setup a Ruby (Rails) web application to use and follow
the JSON:API specifications.The idea is simple, JSONAPI.rb offers a bunch of modules/mixins/glue,
add them to your controllers, call some methods, _profit_!Main goals:
* No _magic_ please
* No DSLs please
* Less code, less maintenance
* Good docs and test coverage
* Keep it up-to-date (or at least tell people this is for _grabs_)The available features include:
* object serialization (powered by JSON:API Serializer, was `fast_jsonapi`)
* [error handling](https://jsonapi.org/format/#errors) (parameters,
validation, generic errors)
* fetching of the data (support for
[includes](https://jsonapi.org/format/#fetching-includes) and
[sparse fields](https://jsonapi.org/format/#fetching-sparse-fieldsets))
* [filtering](https://jsonapi.org/format/#fetching-filtering) and
[sorting](https://jsonapi.org/format/#fetching-sorting) of the data
(powered by Ransack, soft-dependency)
* [pagination](https://jsonapi.org/format/#fetching-pagination) support## But how?
Mainly by leveraging [JSON:API Serializer](https://github.com/jsonapi-serializer/jsonapi-serializer)
and [Ransack](https://github.com/activerecord-hackery/ransack).Thanks to everyone who worked on these amazing projects!
## Sponsors
I'm grateful for the following companies for supporting this project!
## Installation
Add this line to your application's Gemfile:
```ruby
gem 'jsonapi.rb'
```And then execute:
$ bundle
Or install it yourself as:
$ gem install jsonapi.rb
## Usage
* [Object serialization](#object-serialization)
* [Collection meta](#collection-meta)
* [Error handling](#error-handling)
* [Includes and sparse fields](#includes-and-sparse-fields)
* [Filtering and sorting](#filtering-and-sorting)
* [Sorting using expressions](#sorting-using-expressions)
* [Pagination](#pagination)
* [Deserialization](#deserialization)---
To enable the support for Rails, add this to an initializer:
```ruby
# config/initializers/jsonapi.rb
require 'jsonapi'JSONAPI::Rails.install!
```This will register the mime type and the `jsonapi` and `jsonapi_errors`
renderers.### Object serialization
The `jsonapi` renderer will try to guess and resolve the serializer class based
on the object class, and if it is a collection, based on the first item in the
collection.The naming scheme follows the `ModuleName::ClassNameSerializer` for an instance
of the `ModuleName::ClassName`.Please follow the
[JSON:API Serializer guide](https://github.com/jsonapi-serializer/jsonapi-serializer#serializer-definition)
on how to define a serializer.To provide a different naming scheme implement the `jsonapi_serializer_class`
method in your resource or application controller.Here's an example:
```ruby
class CustomNamingController < ActionController::Base# ...
private
def jsonapi_serializer_class(resource, is_collection)
JSONAPI::Rails.serializer_class(resource, is_collection)
rescue NameError
# your serializer class naming implementation
end
end
```To provide extra parameters to the serializer,
implement the `jsonapi_serializer_params` method.Here's an example:
```ruby
class CustomSerializerParamsController < ActionController::Base# ...
private
def jsonapi_serializer_params
{
first_name_upcase: params[:upcase].present?
}
end
end
```#### Collection meta
To provide meta information for a collection, provide the `jsonapi_meta`
controller method.Here's an example:
```ruby
class MyController < ActionController::Base
def index
render jsonapi: Model.all
endprivate
def jsonapi_meta(resources)
{ total: resources.count } if resources.respond_to?(:count)
end
end
```### Error handling
`JSONAPI::Errors` provides a basic error handling. It will generate a valid
error response on exceptions from strong parameters, on generic errors or
when a record is not found.To render the validation errors, just pass it to the error renderer.
To use an exception notifier, overwrite the
`render_jsonapi_internal_server_error` method in your controller.Here's an example:
```ruby
class MyController < ActionController::Base
include JSONAPI::Errorsdef 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
endprivate
def render_jsonapi_internal_server_error(exception)
# Call your exception notifier here. Example:
# Raven.capture_exception(exception)
super(exception)
end
end
```### _Includes_ and sparse fields
`JSONAPI::Fetching` provides support on inclusion of related resources and
serialization of only specific fields.Here's an example:
```ruby
class MyController < ActionController::Base
include JSONAPI::Fetchingdef index
render jsonapi: Model.all
endprivate
# Overwrite/whitelist the includes
def jsonapi_include
super & ['wanted_attribute']
end
end
```This allows you to run queries like:
```bash
$ curl -X GET /api/resources?fields[model]=model_attr,relationship
```### Filtering and sorting
`JSONAPI::Filtering` uses the power of
[Ransack](https://github.com/activerecord-hackery/ransack#search-matchers)
to filter and sort over a collection of records.
The support is pretty extended and covers also relationships and composite
matchers.Please add `ransack` to your `Gemfile` in order to benefit from this functionality!
Here's an example:
```ruby
class MyController < ActionController::Base
include JSONAPI::Filteringdef index
allowed = [:model_attr, :relationship_attr]jsonapi_filter(Model.all, allowed) do |filtered|
render jsonapi: filtered.result
end
end
end
```This allows you to run queries like:
```bash
$ curl -X GET \
/api/resources?filter[model_attr_or_relationship_attr_cont_any]=value,name\
&sort=-model_attr,relationship_attr
```#### Sorting using expressions
You can use basic aggregations like `min`, `max`, `avg`, `sum` and `count`
when sorting. This is an optional feature since SQL aggregations require
grouping. To enable expressions along with filters, use the option flags:```ruby
options = { sort_with_expressions: true }
jsonapi_filter(User.all, allowed_fields, options) do |filtered|
render jsonapi: filtered.result.group('id').to_a
end
```This allows you to run queries like:
```bash
$ curl -X GET /api/resources?sort=-model_attr_sum
```### Pagination
`JSONAPI::Pagination` provides support for paginating model record sets as long
as enumerables.Here's an example:
```ruby
class MyController < ActionController::Base
include JSONAPI::Paginationdef index
jsonapi_paginate(Model.all) do |paginated|
render jsonapi: paginated
end
endend
```This will generate the relevant pagination _links_.
If you want to add the pagination information to your meta,
use the `jsonapi_pagination_meta` method:```ruby
def jsonapi_meta(resources)
pagination = jsonapi_pagination_meta(resources){ pagination: pagination } if pagination.present?
end```
If you want to change the default number of items per page or define a custom logic to handle page size, use the
`jsonapi_page_size` method:```ruby
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
```
### Deserialization`JSONAPI::Deserialization` provides a helper to transform a `JSONAPI` document
into a flat dictionary that can be used to update an `ActiveRecord::Base` model.Here's an example using the `jsonapi_deserialize` helper:
```ruby
class MyController < ActionController::Base
include JSONAPI::Deserializationdef 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
end
```The `jsonapi_deserialize` helper accepts the following options:
* `only`: returns exclusively attributes/relationship data in the provided list
* `except`: returns exclusively attributes/relationship which are not in the list
* `polymorphic`: will add and detect the `_type` attribute and class to the
defined list of polymorphic relationshipsThis functionality requires support for _inflections_. If your project uses
`active_support` or `rails` you don't need to do anything. Alternatively, we will
try to load a lightweight alternative to `active_support/inflector` provided
by the `dry/inflector` gem, please make sure it's added if you want to benefit
from this feature.## Development
After checking out the repo, run `bundle` to install dependencies.
Then, run `rake spec` to run the tests.
To install this gem onto your local machine, run `bundle exec rake install`.
To release a new version, update the version number in `version.rb`, and then
run `bundle exec rake release`, which will create a git tag for the version,
push git commits and tags, and push the `.gem` file to
[rubygems.org](https://rubygems.org).## Contributing
Bug reports and pull requests are welcome on GitHub at
https://github.com/stas/jsonapi.rbThis project is intended to be a safe, welcoming space for collaboration, and
contributors are expected to adhere to the
[Contributor Covenant](http://contributor-covenant.org) code of conduct.## License
The gem is available as open source under the terms of the
[MIT License](https://opensource.org/licenses/MIT).