JsonApiToolbox

This toolbox serve as a JSON API helper within Guide TI specs

The current features are:

  • Integrates the gems jsonapi-serializable, json-api-vanilla and log_toolbox
  • Rspec support through a series of shares examples
  • Suport for JSON API services

Installation

Add this line in your Gemfile:

gem 'json_api_toolbox'

then execute:

$ bundle install

For rspec support, add this line on your rails_helper.rb:

require 'json_api_toolbox/rspec'

Usage Examples

You can check some gem uses within the examples below:

Service

class MyService < JsonApiToolbox::Service
  BASE_URL = 'http://localhost:3000/my_model'

  class << self
    def all(includes: nil, query_string: nil)
      get(url: BASE_URL, includes: includes, query_string: query_string)
    end

    def find(id, includes: includes)
      get(url: "#{BASE_URL}/#{id}", includes: includes)
    end

    def create(payload)
      post(url: BASE_URL, body: payload)
    end

    def update(payload)
      patch(url: "#{BASE_URL}/#{payload.delete(:id)}", body: payload)
    end
  end
end

Renderizable

A simple render:

render_object(Quota.all)

To render an object with a custom serializable, you will need to send a Hash that contains a key called 'class' and its values must be another Hash. In this new Hash, the key must be 'Hash' and the value must be your Serializable.

render_object(QuotaGap.all, class: { Hash: SerializableQuotaGap })

Paginable

To render a collection with a json api pagination, you will need to send a Hash that contains two keys called 'links' and 'meta', and its values must be Hashs.

class MyController
  include JsonApiToolbox::Paginable

  def index
    collection = MyModel
                 .all
                 .paginate(page: params[:page],
                           per_page: params[:per_page])
    render_object(collection, links: pagination(collection),
                              meta: pagination_meta(collection))
  end
end

Rspec Shared Examples

it_behaves_like 'a http method'

  • validate if your response have http status 200

it_behaves_like 'a get method'

  • validate if your response have http status 200
  • validate if your response responde to body method

it_behaves_like 'a json api response with included node'

  • validate if yor response.body has included node

it_behaves_like 'a get with jsonapi with default value of', SomeModel

  • validate if all attributes are present on your data based on the current criteria:

    1. for enums who have _cd in the end of attribute name, _cd is removed.

    ex: enum_cd => enum

    1. id attributes are removed from validation
    2. for attributes who have _id in the end of attribute name, they are removed from validation

it_behaves_like 'a json api response with all relations of', SomeModel

  • validate if all relations are included on your data

it_behaves_like 'a failed attempt to retrieve a resource'

  • checks if the api response will include an error when find raise a exception retrieving a resource.

Test example

# frozen_string_literal: true

require 'rails_helper'

RSpec.describe ManagersController, type: :controller do
  let(:body) { JSON.parse(response.body) }
  let(:data) { body['data'] }

  describe 'GET' do
    let!(:manager) { create(:manager) }
    let(:params) { {} }

    describe '#index' do
      let(:data) { body['data'].first }

      before { get :index, params: params }

      it_behaves_like 'a get method'
      it_behaves_like 'a json api response with all relations of', Manager
      it_behaves_like 'a get with jsonapi with default value of', Manager

      context 'including contacts' do
        let(:params) { { includes: :contacts } }
        it { expect(data['relationships']['contacts']['data'].size).to eq(1) }
      end
    end

    describe '#show' do
      before { get :show, params: { id: manager.id } }

      it_behaves_like 'a get method'
      it_behaves_like 'a json api response with included node'
      it_behaves_like 'a json api response with all relations of', Manager
      it_behaves_like 'a get with jsonapi with default value of', Manager

      context 'When the manager does not exist' do
        before { get :show, params: { id: 300 } }

        it_behaves_like 'a failed attempt to retrieve a resource'
      end
    end
  end

  describe 'POST' do
    describe '#create' do
      let(:params) do
        attributes_for(:manager).merge(
          contacts: attributes_for_list(:contact, 2)
        )
      end

      before { post :create, params: params }

      it_behaves_like 'a get method'
      it_behaves_like 'a json api response with included node'
      it_behaves_like 'a json api response with all relations of', Manager
      it_behaves_like 'a get with jsonapi with default value of', Manager

      it { expect(data['relationships']['contacts']['data'].count).to eq(2) }
    end
  end

  describe 'PATCH' do
    describe '#update' do
      let(:manager) { create(:manager) }
      let(:new_name) { 'Manager 100' }
      let(:params) do
        {
          id: manager.id,
          name: new_name,
          short_name: manager.short_name
        }
      end

      before { post :update, params: params }

      it_behaves_like 'a get method'
      it_behaves_like 'a json api response with included node'
      it_behaves_like 'a json api response with all relations of', Manager
      it_behaves_like 'a get with jsonapi with default value of', Manager

      it 'validates if values were updated' do
        expect(data['attributes']['name']).to eq(new_name)
      end

      context 'When the manager does not exist' do
        before { get :show, params: { id: 300 } }

        it_behaves_like 'a failed attempt to retrieve a resource'
      end
    end
  end
end

Development

To change the gem is simple, just clone this repository and run the bin/setup script

Then you can make your changes and check them with rspec or rubocop ..

On docker

Building

  docker build . -t json-api-toolbox-dev

Running tests

  docker run --rm -it -v "$(echo $HOME)/.ssh:/root/.ssh" -v "$(pwd):/gem" json-api-toolbox-dev

Contributing

To be written