6
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【Laravel】API開発でページネーションを実装する

Posted at

はじめに

フロント側: 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": "&laquo; 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 &raquo;",
                "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に見えるだろうな…と思ったり。

情報共有やメソッド名の工夫は必要かもしれない。

参考記事

6
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?