librariesio/api-pagination

Name: api-pagination

Owner: Libraries.io

Description: :page_facing_up: Link header pagination for Rails and Grape APIs.

Created: 2016-08-01 22:48:08.0

Updated: 2016-08-01 22:48:09.0

Pushed: 2016-03-03 07:45:05.0

Homepage:

Size: 145

Language: Ruby

GitHub Committers

UserMost Recent Commit# Commits

Other Committers

UserEmailMost Recent Commit# Commits

README

api-pagination

Build Status Coverage Climate Dependencies gittip

Paginate in your headers, not in your response body. This follows the proposed RFC-5988 standard for Web linking.

Installation

In your Gemfile:

quires Rails (Rails-API is also supported), or Grape
.10.0 or later. If you're on an earlier version of
ape, use api-pagination v3.0.2.
'rails', '>= 3.0.0'
'rails-api'
'grape', '>= 0.10.0'

en choose your preferred paginator from the following:
'kaminari'
'will_paginate'

nally...
'api-pagination'
Configuration (optional)

By default, api-pagination will detect whether you're using Kaminari or WillPaginate, and name headers appropriately. If you want to change any of the configurable settings, you may do so:

agination.configure do |config|
If you have both gems included, you can choose a paginator.
nfig.paginator = :kaminari # or :will_paginate

By default, this is set to 'Total'
nfig.total_header = 'X-Total'

By default, this is set to 'Per-Page'
nfig.per_page_header = 'X-Per-Page'

Optional: set this to add a header with the current page number.
nfig.page_header = 'X-Page'

Optional: what parameter should be used to set the page option
nfig.page_param = :page
or
nfig.page_param do |params|
params[:page][:number]
d

Optional: what parameter should be used to set the per page option
nfig.per_page_param = :per_page
or
nfig.per_page_param do |params|
params[:page][:size]
d

Rails

In your controller, provide a pageable collection to the paginate method. In its most convenient form, paginate simply mimics render:

s MoviesController < ApplicationController
GET /movies
f index
movies = Movie.all # Movie.scoped if using ActiveRecord 3.x

paginate json: movies
d

GET /movies/:id/cast
f cast
actors = Movie.find(params[:id]).actors

# Override how many Actors get returned. If unspecified,
# params[:per_page] (which defaults to 25) will be used.
paginate json: actors, per_page: 10
d

This will pull your collection from the json or xml option, paginate it for you using params[:page] and params[:per_page], render Link headers, and call ActionController::Base#render with whatever you passed to paginate. This should work well with ActiveModel::Serializers. However, if you need more control over what is done with your paginated collection, you can pass the collection directly to paginate to receive a paginated collection and have your headers set. Then, you can pass that paginated collection to a serializer or do whatever you want with it:

s MoviesController < ApplicationController
GET /movies
f index
movies = paginate Movie.all

render json: MoviesSerializer.new(movies)
d

GET /movies/:id/cast
f cast
actors = paginate Movie.find(params[:id]).actors, per_page: 10

render json: ActorsSerializer.new(actors)
d

Note that the collection sent to paginate must respond to your paginator's methods. This is typically fine unless you're dealing with a stock Array. For Kaminari, Kaminari.paginate_array will be called for you behind-the-scenes. For WillPaginate, you're out of luck unless you call require 'will_paginate/array' somewhere. Because this pollutes Array, it won't be done for you automatically.

Grape

With Grape, paginate is used to declare that your endpoint takes a :page and :per_page param. You can also directly specify a :max_per_page that users aren't allowed to go over. Then, inside your API endpoint, it simply takes your collection:

s MoviesAPI < Grape::API
rmat :json

sc 'Return a paginated set of movies'
ginate
t do
# This method must take an ActiveRecord::Relation
# or some equivalent pageable set.
paginate Movie.all
d

ute_param :id do
desc "Return one movie's cast, paginated"
# Override how many Actors get returned. If unspecified,
# params[:per_page] (which defaults to 25) will be used.
# There is no default for `max_per_page`.
paginate per_page: 10, max_per_page: 200
get :cast do
  paginate Movie.find(params[:id]).actors
end
d

Headers

Then curl --include to see your header-based pagination in action:

rl --include 'https://localhost:3000/movies?page=5'
/1.1 200 OK
: <http://localhost:3000/movies?page=1>; rel="first",
ttp://localhost:3000/movies?page=173>; rel="last",
ttp://localhost:3000/movies?page=6>; rel="next",
ttp://localhost:3000/movies?page=4>; rel="prev"
l: 4321
Page: 10
.
A Note on Kaminari and WillPaginate

api-pagination requires either Kaminari or WillPaginate in order to function, but some users may find themselves in situations where their application includes both. For example, you may have included ActiveAdmin (which uses Kaminari for pagination) and WillPaginate to do your own pagination. While it's suggested that you remove one paginator gem or the other, if you're unable to do so, you must configure api-pagination explicitly:

agination.configure do |config|
nfig.paginator = :will_paginate

If you don't do this, an annoying warning will print once your app starts seeing traffic. You should also configure Kaminari to use a different name for its per_page method (see https://github.com/activeadmin/activeadmin/wiki/How-to-work-with-will_paginate):

nari.configure do |config|
nfig.page_method_name = :per_page_kaminari


This work is supported by the National Institutes of Health's National Center for Advancing Translational Sciences, Grant Number U24TR002306. This work is solely the responsibility of the creators and does not necessarily represent the official views of the National Institutes of Health.