LaravelでAPIを作るとき、一覧取得を配列でそのまま返すと、フロント側で「次のページがあるのか」「今何ページ目なのか」を判断しにくくなります。そこで使いたいのが paginate() と Resource Collection の組み合わせです。
この記事では、記事一覧APIを例に、ページネーション付きJSONを返す実装を作ります。
ルート
<?php
use App\Http\Controllers\Api\ArticleController;
use Illuminate\Support\Facades\Route;
Route::get('/articles', [ArticleController::class, 'index']);
Controller
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Http\Resources\ArticleResource;
use App\Models\Article;
use Illuminate\Http\Request;
class ArticleController extends Controller
{
public function index(Request $request)
{
$perPage = min((int) $request->query('per_page', 10), 50);
$articles = Article::query()
->where('is_published', true)
->latest('published_at')
->paginate($perPage)
->withQueryString();
return ArticleResource::collection($articles);
}
}
Resource
<?php
namespace App\Http\Resources;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class ArticleResource extends JsonResource
{
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'title' => $this->title,
'slug' => $this->slug,
'excerpt' => $this->excerpt,
'published_at' => optional($this->published_at)->toISOString(),
];
}
}
フロントエンドから取得する例
async function fetchArticles(page = 1) {
const params = new URLSearchParams({
page: String(page),
per_page: "10",
});
const response = await fetch(`/api/articles?${params.toString()}`);
if (!response.ok) {
throw new Error("記事一覧の取得に失敗しました。");
}
return response.json();
}
const result = await fetchArticles(1);
console.log(result.data);
console.log(result.links.next);
console.log(result.meta.current_page);
返ってくるJSONの見方
| キー | 意味 |
|---|---|
data | 現在ページに含まれる記事一覧 |
links | 前後ページや先頭、末尾ページへのURL |
meta | 現在ページ、最終ページ、総件数などのページ情報 |
実務で気をつけること
per_pageは上限を決めて、重いリクエストを防ぐ- 検索条件や並び順を維持したい場合は
withQueryString()を使う - 件数が非常に多く無限スクロール中心なら
cursorPaginate()も検討する - Resourceで返す項目を絞り、DBの内部構造をそのまま公開しない
あわせて読みたい
- LaravelでAPI ResourceとValidationを使ってJSON APIを整える方法
- LaravelとNext.jsでSSGサイトを作る方法
- JavaScriptで検索条件をURLに保存する方法【URLSearchParams】
- FlutterでAPI通信をRepositoryに分けてFutureBuilderで表示する方法