Пагинация в API
Два подхода
- Серверная пагинация — клиент запрашивает страницы, сервер отдаёт часть записей и метаданные
- Клиентская пагинация — сервер отдаёт всё, клиент делит на страницы
Для больших данных используют серверную.
Пагинация в Laravel
$posts = Post::paginate(15);
return PostResource::collection($posts);
Ответ:
{
"data": [...],
"links": {
"first": "http://api.example.com/posts?page=1",
"last": "http://api.example.com/posts?page=5",
"prev": null,
"next": "http://api.example.com/posts?page=2"
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 5,
"per_page": 15,
"to": 15,
"total": 73
}
}
Параметр per_page
Можно разрешить клиенту задавать размер страницы:
$perPage = min($request->integer('per_page', 15), 100);
$posts = Post::paginate($perPage);
Ограничение min защищает от запроса per_page=1000000.
simplePaginate
Не считает общее количество:
$posts = Post::simplePaginate(15);
Ответ:
{
"data": [...],
"links": {
"prev": null,
"next": "http://api.example.com/posts?page=2"
}
}
Быстрее, если общее количество не нужно.
cursorPaginate
Для больших таблиц:
$posts = Post::orderBy('id')->cursorPaginate(15);
Использует курсор вместо offset. Работает за константное время независимо от номера страницы.
Сохранение фильтров
$posts = $query->paginate(15)->withQueryString();
Все query-параметры сохранятся в ссылках пагинации.
Кастомный формат
return response()->json([
'items' => PostResource::collection($posts->items()),
'total' => $posts->total(),
'page' => $posts->currentPage(),
'per_page' => $posts->perPage(),
]);