RailsのAPIでpaginationを考える
5月になり、もう夏か〜となったら6月梅雨シーズンで半袖が寒い〜というあるあるを感じています...
今回はタイトルの通り、自社のサービスのpaginationを考え直す機会があったのでそのアウトプットです。
Railsには色んなpaginationのライブラリがあったり、結局paginationで必要なパラメーターやレスポンスってなんだ..?となったので同じような悩みを抱えた方の参考になれば嬉しいです。
やりたいこと
前述の通り、Ruby on Railsであるmodelのindexでpaginationを含んだレスポンスを返したいです。
Rubyのpaginationのライブラリはviewも加味したライブラリが多いため選定には少し苦戦しました。
ライブラリ選定
paginationの実装は以下の手段があがりました。
自前で実装する
ライブラリをできるだけ削り、できるだけ軽量なRailsを保つようにしているためこの案が出てきました。
- メリット
- 軽量なRailsを保てる(はず)
- paginationの実装がライブラリまでいかなくても追える
- デメリット
- 車輪の再開発
- メンテコスト
別のライブラリを入れる場合でも同じことが言えるなぁって思いながら↑書いてましたw
pagyを入れる
GitHubのREADMEにもある通り、kaminariなど他ライブラリと比べて軽量らしいです。
(手元で比較していないため らしい
にとどめておきます)
- メリット
- 他のライブラリと比べて軽量そう
- 新しいライブラリなのでイケてる
- デメリット
- version upが頻繁にある
- これはいい面でもあり運用面を考えると辛くなる面もあると思います
- https://rubygems.org/gems/pagy/versions
-
ライブラリからパラメータにアクセスしている
- できるだけライブラリの振る舞いを制御したく、自分たちのチームではここは考慮すべき点でした
- version upが頻繁にある
kaminariを入れる
有名なライブラリも候補にあげました。
- メリット
- チーム内で導入した実績がある
- デメリット
- pagyと比べて重そう..?
- APIサーバーであるためUI部分のライブラリは削りたい
結果
色々試してみた結果、自分たちのチームでは kaminari
を利用することになりました。
理由としては以下です。
- チーム内で導入した実績がある
- メンテコスト
- ライブラリを使う
- version upが頻繁ではない
kaminari
はrelease tag自体は最新が2021年12月ですが、commitを見ると今もメンテされてそう(めちゃめちゃありがたい)なのでありがたく使わせてもらうことにしました。
スキーマ定義
パラメータは特に変わったことはしておらず、何ページ目かと1ページあたりの表示数を受け付けています。
parameters:
- name: page
in: query
description: ページ番号
required: false
schema:
type: integer
- name: perPage
in: query
description: 1ページあたりの表示数
required: false
schema:
type: integer
レスポンスとしては startPosition
と endPosition
は珍しいかなと思います。
これは要件としてどこからどこまでを表示しているかを返す必要があったため入れています。
from
と to
とかにしても良いかなと思いますね。
type: object
properties:
totalPage:
type: integer
description: 全体のページ数
currentPage:
type: integer
description: 現在のページ番号
totalCount:
type: integer
description: 全体のレコード数
startPosition:
type: integer
description: 現在のページの開始位置
endPosition:
type: integer
description: 現在のページの終了位置
required:
- totalPage
- currentPage
- totalCount
- startPosition
- endPosition
controller実装
レスポンスでは kaminari
のおかげで生えているメソッドを駆使して返しています。
def hoge
page = params[:page] || 0
per_page = params[:per_page] || 20
hoges = Hoge.page(page).per(per_page)
render json: {
hoges: hoges.map do |hoge|
{
id: hoge.id,
name: hoge.name
}
end,
pagination: {
totalPage: hoges.total_pages,
currentPage: hoges.current_page,
totalCount: hoges.total_count,
startPosition: hoges.count.zero? ? 0 : hoges.offset_value + 1,
endPosition: hoges.offset_value + hoges.count
}
}.to_json
end
まとめ
自分たちのチームでは暫定として kaminari
を使うことにしましたが、APIサーバーとしては以下のライブラリは必要がないので改善していく予定です!!
あくまで自分たちのチームではという前提なので他のチームや状況であれば pagy
や will_paginate
などを導入するかと思います。
また、導入にあたりそこまで時間がなかったためより良いライブラリなどがあればぜひ教えてほしいです!!
kaminari (1.2.2)
activesupport (>= 4.1.0)
kaminari-actionview (= 1.2.2) <-これ!!!!!!!!!!!!!!!!
kaminari-activerecord (= 1.2.2)
kaminari-core (= 1.2.2)
kaminari-actionview (1.2.2) <-これ!!!!!!!!!!!!!!!!
actionview
kaminari-core (= 1.2.2)
kaminari-activerecord (1.2.2)
activerecord
kaminari-core (= 1.2.2)
kaminari-core (1.2.2)
Discussion