Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up

📄 Link header pagination for Rails and Grape APIs.

License

NotificationsYou must be signed in to change notification settings

davidcelis/api-pagination

Repository files navigation

Paginate in your headers, not in your response body.This follows the proposedRFC-8288 standard for Web linking.

Installation

In yourGemfile:

# Requires Rails (Rails-API is also supported), or Grape# v0.10.0 or later. If you're on an earlier version of# Grape, use api-pagination v3.0.2.gem'rails','>= 3.0.0'gem'rails-api'gem'grape','>= 0.10.0'# Then choose your preferred paginator from the following:gem'pagy'gem'kaminari'gem'will_paginate'# Finally...gem'api-pagination'

Configuration (optional)

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

ApiPagination.configuredo |config|# If you have more than one gem included, you can choose a paginator.config.paginator=:kaminari# or :will_paginate# By default, this is set to 'Total'config.total_header='X-Total'# By default, this is set to 'Per-Page'config.per_page_header='X-Per-Page'# Optional: set this to add a header with the current page number.config.page_header='X-Page'# Optional: set this to add other response format. Useful with tools that define :jsonapi formatconfig.response_formats=[:json,:xml,:jsonapi]# Optional: what parameter should be used to set the page optionconfig.page_param=:page# orconfig.page_paramdo |params|params[:page][:number]ifparams[:page].is_a?(ActionController::Parameters)end# Optional: what parameter should be used to set the per page optionconfig.per_page_param=:per_page# orconfig.per_page_paramdo |params|params[:page][:size]ifparams[:page].is_a?(ActionController::Parameters)end# Optional: Include the total and last_page link header# By default, this is set to true# Note: When using kaminari, this prevents the count call to the databaseconfig.include_total=falseend

Pagy-specific configuration

Pagy does not have a built-in way to specify a maximum number of items per page, butapi-pagination will check if you've set a:max_per_page variable. To configure this, you can use the following code somewhere in an initializer:

Pagy::DEFAULT[:max_per_page]=100

If left unconfigured, clients can request as many items per page as they wish, so it's highly recommended that you configure this.

Rails

In your controller, provide a pageable collection to thepaginate method. In its most convenient form,paginate simply mimicsrender:

classMoviesController <ApplicationController# GET /moviesdefindexmovies=Movie.all# Movie.scoped if using ActiveRecord 3.xpaginatejson:moviesend# GET /movies/:id/castdefcastactors=Movie.find(params[:id]).actors# Override how many Actors get returned. If unspecified,# params[:per_page] (which defaults to 25) will be used.paginatejson:actors,per_page:10endend

This will pull your collection from thejson orxml option, paginate it for you usingparams[:page] andparams[:per_page], render Link headers, and callActionController::Base#render with whatever you passed topaginate. This should work well withActiveModel::Serializers. However, if you need more control over what is done with your paginated collection, you can pass the collection directly topaginate 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:

classMoviesController <ApplicationController# GET /moviesdefindexmovies=paginateMovie.allrenderjson:MoviesSerializer.new(movies)end# GET /movies/:id/castdefcastactors=paginateMovie.find(params[:id]).actors,per_page:10renderjson:ActorsSerializer.new(actors)endend

Note that the collection sent topaginatemust 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 callrequire 'will_paginate/array' somewhere. Because this pollutesArray, it won't be done for you automatically. If you use Pagy, it doesn't matter, because Pagy doesn't care what you're paginating. It will just work, as long as the collection responds tocount.

NOTE: In versions 4.4.0 and below, theRails::Pagination module would end up included inActionController::Base even ifActionController::API was defined. As of version 4.5.0, this is no longer the case. If for any reason your API controllers cannot easily changed be changed to inherit fromActionController::API instead, you can manually include the module:

classAPI::ApplicationController <ActionController::BaseincludeRails::Paginationend

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:

classMoviesAPI <Grape::APIformat:jsondesc'Return a paginated set of movies'paginategetdo# This method must take an ActiveRecord::Relation# or some equivalent pageable set.paginateMovie.allendroute_param:iddodesc"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`.paginateper_page:10,max_per_page:200get:castdopaginateMovie.find(params[:id]).actorsenddesc"Return one movie's awards, paginated"# Enforce max_per_page value will add the alowed values# to the swagger docs, and cause grape to return an error# if outside that rangepaginateper_page:10,max_per_page:200,enforce_max_per_page:trueget:awardsdopaginateMovie.find(params[:id]).awardsendendend

Headers

Thencurl --include to see your header-based pagination in action:

$ curl --include'https://localhost:3000/movies?page=5'HTTP/1.1 200 OKLink:<http://localhost:3000/movies?page=1>; rel="first",<http://localhost:3000/movies?page=173>; rel="last",<http://localhost:3000/movies?page=6>; rel="next",<http://localhost:3000/movies?page=4>; rel="prev"Total: 4321Per-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 includedActiveAdmin (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, youmust configure api-pagination explicitly:

ApiPagination.configuredo |config|config.paginator=:will_paginateend

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 itsper_page method (seehttps://github.com/activeadmin/activeadmin/wiki/How-to-work-with-will_paginate):

Kaminari.configuredo |config|config.page_method_name=:per_page_kaminariend

[8]ページ先頭

©2009-2025 Movatter.jp