• Stars
    star
    262
  • Rank 156,136 (Top 4 %)
  • Language
    Ruby
  • License
    MIT License
  • Created almost 6 years ago
  • Updated 4 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Lightweight, simple and maintained JSON:API support for your next Ruby HTTP API.

JSONAPI.rb 🔌

Build Status

So you say you need JSON:API support in your API...

  • hey how did your hackathon go?
  • not too bad, we got Babel set up
  • yep…
  • yep.

— I Am Devloper

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:

But how?

Mainly by leveraging JSON:API Serializer and 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:

gem 'jsonapi.rb'

And then execute:

$ bundle

Or install it yourself as:

$ gem install jsonapi.rb

Usage


To enable the support for Rails, add this to an initializer:

# 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 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:

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:

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:

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
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:

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
end

Includes and sparse fields

JSONAPI::Fetching provides support on inclusion of related resources and serialization of only specific fields.

Here's an example:

class MyController < ActionController::Base
  include JSONAPI::Fetching

  def index
    render jsonapi: Model.all
  end

  private

  # Overwrite/whitelist the includes
  def jsonapi_include
    super & ['wanted_attribute']
  end
end

This allows you to run queries like:

$ curl -X GET /api/resources?fields[model]=model_attr,relationship

Filtering and sorting

JSONAPI::Filtering uses the power of Ransack 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:

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
end

This allows you to run queries like:

$ 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:

options = { sort_with_expressions: true }
jsonapi_filter(User.all, allowed_fields, options) do |filtered|
  render jsonapi: result.group('id').to_a
end

This allows you to run queries like:

$ 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:

class MyController < ActionController::Base
  include JSONAPI::Pagination

  def index
    jsonapi_paginate(Model.all) do |paginated|
      render jsonapi: paginated
    end
  end

end

This will generate the relevant pagination links.

If you want to add the pagination information to your meta, use the jsonapi_pagination_meta method:

  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:

  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:

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
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 relationships

This 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.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/stas/jsonapi.rb

This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.

License

The gem is available as open source under the terms of the MIT License.

More Repositories

1

otp-jwt

One time password (email, SMS) authentication support for HTTP APIs.
Ruby
103
star
2

active_record-pgcrypto

PostgreSQL PGCrypto support for ActiveRecord
Ruby
22
star
3

jquery-image-annotate-php-fork

A fork of jQuery Image Annotation plugin with PHP support
JavaScript
20
star
4

pluginify

A tool to generate a WordPress plugin skeleton. Fork on!
PHP
9
star
5

rspec-rake

RSpec support for testing Rake tasks
Ruby
9
star
6

mina-rbenv-addons

Install and upgrade Ruby and Rbenv with Mina
Ruby
8
star
7

appengine-for-facebook

A light Google AppEngine framework to write Facebook apps
Python
8
star
8

emberjs-requirejs

Ember.js + Require.js (Model, Controller and a View example)
JavaScript
7
star
9

mina-ftp

FTP support for Mina.
Ruby
7
star
10

post-types-calendar

WordPress widget that shows a calendar based on existing post types.
PHP
6
star
11

php-eventbrite

PHP wrapper for Eventbrite API
PHP
6
star
12

mina-s3

Adds AWS S3 support for mina
Ruby
5
star
13

dotfiles

linux(ubuntu), zsh, vim
Vim Script
4
star
14

comma-diacritics

The WordPress plugin searches and replaces the wrong (sedilla) diacritics with the correct ones on data saving
PHP
4
star
15

pagina

Pagina is a Rack web app for Heroku that will use your Dropbox folder for site pages.
Ruby
4
star
16

pos

OpenBravo Pos Fork
Java
4
star
17

contract-servicii

Pentru că e frumos să-ți faci contractele în Markdown
4
star
18

simple-crm

Simple CRM is a WordPress plugin that lets you define custom fields to extend user profiles and it is also a framework for integration with all kind of CRM API webservices
PHP
4
star
19

static-website-boilerplate

Because it sucks to bootstrap static websites.
Ruby
3
star
20

uploads

WordPress uploads have a control panel now
PHP
2
star
21

markdown-wiki

A simple wiki which uses markdown for it's syntax
2
star
22

simple-crm-profile-page

WordPress plugin that adds public profile page support to Simple CRM
PHP
2
star
23

thesis

My Bc. thesis.
TeX
2
star
24

beamer-ubuntu

Ubuntu Beamer Template
TeX
2
star
25

eventbrite

Eventbrite for WordPress
PHP
2
star
26

light-askbot-theme

Askbot Ubuntu Theme (ala askubuntu.com)
JavaScript
2
star
27

rota

WordPress app for basic rota management based on user options
PHP
2
star
28

localize

WordPress plugin to easily switch to any localization from GlotPress
PHP
2
star
29

simple-crm-buddypress-xprofile

Import/Export BuddyPress XProfile data to Simple CRM
PHP
2
star
30

simple-crm-mailchimp

Adds MailChimp Synchronization to Simple CRM
PHP
2
star
31

techtalks-s5

S5 Template for TechTalks
JavaScript
2
star
32

facebook-ideas-app

A Facebook application for submitting ideas with rating system
1
star
33

qa-cleditor

Question2Answer CLEditor Plugin
JavaScript
1
star
34

simple-crm-csv-import

WordPress Simple CRM CSV Import Addon
PHP
1
star
35

jtw

A java twitter client build above jtwitterlib
1
star
36

stas.github.com

Homepage
HTML
1
star
37

student.utcluj.ro

New version of TUCN student portal
PHP
1
star
38

sharedaddy-more-control

WordPress plugin that extends Sharedaddy control over post types
PHP
1
star
39

methane

Campfire desktop client (W|R)IP
Ruby
1
star
40

personal

Personal repository. You know, scripts, dotrc...
Shell
1
star
41

http-rest_client

A simple HTTP API Client built on top of http.rb gem
Ruby
1
star
42

emberjs-jasmine-slides-geekmeet

Ember.js + Jasmine BDD slides from GeekMeet #12 Cluj-Napoca
JavaScript
1
star
43

capistrano-lazy

Capistrano for Lazy
Ruby
1
star
44

simple-crm-mailchimp-widget

Adds MailChimp Subscribe Widget to Simple CRM
PHP
1
star