Low commit activity in last 3 years
A long-lived project that still receives updates
A controller filters engine gem based on jsonapi spec.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies

Development

~> 2.0
~> 3.0
~> 0.59.2
~> 13.0

Runtime

 Project Readme

FetcheableOnApi

JSONAPI-compliant filtering, sorting, and pagination for Rails API controllers, declared in two lines, zero boilerplate.


Gem Version Documentation License

Quick Start

Add the gem:

gem 'fetcheable_on_api'
bundle install
rails generate fetcheable_on_api:install

Declare what's allowed, then apply:

class UsersController < ApplicationController
  filter_by :name, :email, :status
  sort_by :name, :created_at

  def index
    render json: apply_fetcheable(User.all)
  end
end

Your API now supports:

GET /users?filter[name]=john&filter[status]=active
GET /users?sort=name,-created_at
GET /users?page[number]=2&page[size]=25
GET /users?filter[status]=active&sort=-created_at&page[number]=1&page[size]=10

Features

  • 30+ filter predicates, eq, ilike, between, in, gt, lt, and many more, plus custom lambdas
  • Multi-field sorting, comma-separated fields, +/- prefix for direction, case-insensitive option
  • Automatic pagination, page-based with response headers (Pagination-Current-Page, Pagination-Per, Pagination-Total-Pages, Pagination-Total-Count)
  • Association support, filter and sort through ActiveRecord associations
  • Whitelisted by design, only explicitly declared attributes are queryable

Install

Prerequisites: Ruby >= 2.7, Rails >= 5.2 (ActiveSupport >= 5.2, < 9)

Compatibility

Ruby Rails 5.2 Rails 7.0 Rails 7.1 Rails 7.2 Rails 8.0
2.7
3.0
3.1
3.2
3.3
3.4

Bundler (recommended)

# Gemfile
gem 'fetcheable_on_api'
bundle install
rails generate fetcheable_on_api:install

Manual

gem install fetcheable_on_api

Usage

Filtering

filter_by :name                          # default: ilike (partial, case-insensitive)
filter_by :email, with: :eq              # exact match
filter_by :age, with: :gteq             # numeric comparison
filter_by :created_at, with: :between, format: :datetime  # date range

Filter through associations:

filter_by :author, class_name: User, as: 'name'

Custom lambda predicates:

filter_by :full_name, with: ->(collection, value) {
  collection.arel_table[:first_name].matches("%#{value}%").or(
    collection.arel_table[:last_name].matches("%#{value}%")
  )
}
GET /users?filter[name]=john              # partial match
GET /users?filter[status]=active,pending  # multiple values (OR)
GET /users?filter[age]=21                 # numeric
GET /users?filter[author]=jane            # through association

Sorting

sort_by :name, :created_at
sort_by :display_name, lower: true                          # case-insensitive
sort_by :author, class_name: User, as: 'name'              # through association
GET /users?sort=name                # ascending
GET /users?sort=-created_at         # descending
GET /users?sort=status,-created_at  # multiple fields

Pagination

Pagination works automatically. Configure the default page size:

# config/initializers/fetcheable_on_api.rb
FetcheableOnApi.configure do |config|
  config.pagination_default_size = 50  # default: 25
end
GET /users?page[number]=2&page[size]=25

Response headers:

Pagination-Current-Page: 2
Pagination-Per: 25
Pagination-Total-Pages: 8
Pagination-Total-Count: 200

Combining Everything

class PostsController < ApplicationController
  filter_by :title, :published
  filter_by :author, class_name: User, as: 'name'
  sort_by :title, :created_at
  sort_by :author, class_name: User, as: 'name'

  def index
    render json: apply_fetcheable(Post.joins(:author).includes(:author))
  end
end
GET /posts?filter[author]=john&filter[published]=true&sort=-created_at&page[number]=1&page[size]=10

Documentation

Contributing

Contributions welcome. See CODE_OF_CONDUCT.md for community guidelines.

bin/setup          # install dependencies
rake spec          # run tests
bin/console        # interactive console

Acknowledgments

Thanks to all contributors.

Built on top of Arel and the JSONAPI specification.

License

MIT