Урок 06

Пагинация в 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(),
]);