はじめに
フロント側: Next.js
× API側: Laravel
という構成で開発をしており、フロント側からAPIの /blogs?page=2
へリクエストすると2ページ目を取得、 /blogs?page=3
へリクエストすると3ページ目を取得というように、ページネーション に対応したAPIを実装したい場面があった。
Laravel
にはページネーション機能があるが、API開発をしているときにページネーションに対応すれば良いのだろう?と悩んで調べたところ、すごく簡単でフレームワークってすごい!と驚いた。
この記事では Laravel
のページネーション機能の基本的な使い方と、API開発での実装方法をまとめておく。
コントローラーの記述
最新のブログ記事から順に10件ずつ取得する場合を例に挙げる。
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\Blog;
use Illuminate\Http\Request;
class BlogController extends Controller
{
public function index()
{
return Blog::latest()->paginate(10);
}
}
Laravelの paginate
メソッドの基本的な使用方法は、 paginate
メソッドの引数にページ毎に表示したいアイテム数を渡すだけ。
これだけで、HTTPリクエストのURLのクエリパラメータから現在のページを検出し、 limit
(1ページで返すデータ数)や offset
(開始位置)を自動的に処理してくれる。
Request
オブジェクトを受け取るとか、クエリパラメータを受け取るような記述は一切必要ない。
もちろん where
句などと組み合わせて使用することもできる。
Blog::where('user_id', '1')->paginate(10);
ルーティングの定義
api.php
にルーティングを定義する。
<?php
use App\Http\Controllers\Api\BlogController;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
Route::get('blogs', [BlogController::class, 'index']);
ここでもクエリパラメータを受け取る記述は必要なく、先述の通り paginate
メソッドを使ってさえいれば、あとはLaravelが自動的にクエリパラメータを検出して処理してくれる。
APIリクエストを送ってみる
定義したURL宛にAPIリクエストを送ってみると、以下のような形式のレスポンスが返ってくる。
http://localhost/api/blogs
(1ページ目)にアクセスした場合
{
"items": {
"current_page": 1,
"data": [
{
"id": 11,
"title": "タイトル11",
},
{
"id": 10,
"title": "タイトル10",
},
//****** 中略 ******//
{
"id": 2,
"title": "タイトル2",
}
],
"first_page_url": "http://localhost/api/blogs?page=1",
"from": 1,
"last_page": 2,
"last_page_url": "http://localhost/api/blogs?page=2",
"links": [
{
"url": null,
"label": "« Previous",
"active": false
},
{
"url": "http://localhost/api/blogs?page=1",
"label": "1",
"active": true
},
{
"url": "http://localhost/api/blogs?page=2",
"label": "2",
"active": false
},
{
"url": "http://localhost/api/blogs?page=2",
"label": "Next »",
"active": false
}
],
"next_page_url": "http://localhost/api/blogs?page=2",
"path": "http://localhost/api/blogs",
"per_page": "10",
"prev_page_url": null,
"to": 10,
"total": 11
}
}
レスポンスの中の data
に、ブログ記事データが最新から順に格納されている。
また "current_page": 1,
の現在ページや、 "last_page": 2,
の何ページ目まで存在するかだったり、 "next_page_url": "http://localhost/api/blogs?page=2"
の次ページを取得するためのURLなど、色々な情報を自動的にレスポンスに組み込んでくれている。
このように、API側でやることは paginate
メソッドを使用してDBからデータを取得することのみで、あとはフロント側から1ページ目であれば /blogs
、2ページ目であれば /blogs?page=2
というようにページ数をクエリパラメータで指定してリクエストを送るだけで、ページネーション が実装できる。
さいごに
paginate
メソッドを使うだけであとのことはLaravelが全て自動的に行ってくれて、返されるレスポンスも非常に丁寧で充実していて、これぞフレームワークの便利さ!と感動した。
ただ逆に言えば、 paginate
メソッドが実装されている箇所を見るまでは、ページネーションに対応したAPIだと一切わからないので、他の開発メンバーがルーティング定義ファイルを見ただけではただの全件取得APIに見えるだろうな…と思ったり。
情報共有やメソッド名の工夫は必要かもしれない。
参考記事