Pagination в REST API
Введение: страницы книги 📖
Никто не читает книгу целиком одной страницей — мы листаем.
Пагинация в API делает то же самое: выдаёт данные порциями.
Пагинация в API делает то же самое: выдаёт данные порциями.
💡 Совет: без пагинации API «тонет» на больших списках.
✅ Вывод: пагинация — обязательный инструмент для списков.
✅ Вывод: пагинация — обязательный инструмент для списков.
Проблема → решение
Проблема: большие списки грузятся долго и перегружают сервер.
Решение: разбивать выдачу на страницы и возвращать метаданные.
Решение: разбивать выдачу на страницы и возвращать метаданные.
✅ Вывод: пагинация повышает скорость и стабильность.
Чем помогает и как работает
Пагинация уменьшает размер ответа и защищает сервер от перегрузки.
Она делает списки быстрыми и управляемыми.
Как это работает:
- Клиент передаёт
page/limitилиcursor. - Сервер возвращает часть списка и метаданные/nextCursor.
- Клиент запрашивает следующую страницу при необходимости.
✅ Вывод: пагинация обеспечивает скорость и предсказуемость выдачи.
Ключевые термины (простыми словами)
- Page / Limit — номер страницы и размер.
- Offset — смещение от начала списка.
- Cursor — указатель на конкретный элемент.
- Total — общее количество записей.
- Next/Prev — ссылки на следующую и предыдущую страницу.
✅ Вывод: термины помогают выбирать правильный тип пагинации.
Самое важное (must‑know)
- Всегда фиксируйте сортировку — иначе страницы «прыгают».
- Ограничивайте limit (например, max 100).
- Large datasets → cursor‑pagination.
- Total может быть дорогим — не всегда возвращайте.
- Пагинация должна быть документирована.
✅ Вывод: без этих правил пагинация даёт хаос.
1. Offset‑pagination (page/limit)
Назначение: простое разбиение списка на страницы.
Простыми словами: «дай 2‑ю страницу по 20 элементов».
Аналогия: листаем каталог по номерам страниц.
Простыми словами: «дай 2‑ю страницу по 20 элементов».
Аналогия: листаем каталог по номерам страниц.
Пример:
GET /courses?page=2&limit=20🔎 Как это происходит на практике:
- Клиент запрашивает
page=2&limit=20. - Сервер считает offset = 20 и выбирает нужный диапазон.
- Возвращает вторую страницу по 20 элементов.
Характеристики:
- ✅ простая реализация;
- ✅ удобно для UI;
- ✅ плохо для очень больших списков.
Когда использовать: средние списки и интерфейсы.
✅ Вывод: page/limit — базовый вариант.
✅ Вывод: page/limit — базовый вариант.
2. Cursor‑pagination
Назначение: надёжная пагинация для больших данных.
Простыми словами: следующий список начинается «после этого элемента».
Аналогия: закладка в книге.
Простыми словами: следующий список начинается «после этого элемента».
Аналогия: закладка в книге.
Пример:
GET /courses?cursor=abc123&limit=20🔎 Как это происходит на практике:
- Клиент получает
nextCursorиз ответа. - Отправляет следующий запрос с
cursor=.... - Сервер возвращает элементы после курсора.
Характеристики:
- ✅ стабильность при изменениях;
- ✅ быстро на больших данных;
- ✅ чуть сложнее для клиента.
Когда использовать: большие базы и активные изменения.
✅ Вывод: cursor — стандарт для больших API.
✅ Вывод: cursor — стандарт для больших API.
3. Метаданные пагинации
Назначение: помочь клиенту навигировать.
Простыми словами: сервер подсказывает, есть ли следующая страница.
Аналогия: оглавление с номерами страниц.
Простыми словами: сервер подсказывает, есть ли следующая страница.
Аналогия: оглавление с номерами страниц.
Пример:
{ "data": [...], "page": 2, "limit": 20, "total": 240}🔎 Как это происходит на практике:
- Сервер возвращает
dataи метаданные (page/limit/total). - Клиент строит пагинацию в UI.
- При больших данных total может быть отключён.
Характеристики:
- ✅ клиент понимает, сколько страниц;
- ✅ легче строить UI;
- ✅ total может быть дорогим.
Когда использовать: когда UI показывает количество страниц.
✅ Вывод: метаданные = удобство клиента.
✅ Вывод: метаданные = удобство клиента.
4. Стабильная сортировка
Назначение: избежать «перепрыгивания» записей.
Простыми словами: одинаковый порядок для всех страниц.
Аналогия: книги на полке всегда стоят одинаково.
Простыми словами: одинаковый порядок для всех страниц.
Аналогия: книги на полке всегда стоят одинаково.
Пример:
GET /courses?sort=created_at_desc&page=1🔎 Как это происходит на практике:
- Клиент задаёт
sort=created_at_desc. - Сервер фиксирует порядок выдачи.
- Страницы не «прыгают» при обновлениях.
Характеристики:
- ✅ стабильность;
- ✅ отсутствие дублей/пропусков;
- ✅ важно для offset.
Когда использовать: всегда при пагинации.
✅ Вывод: сортировка — обязательна.
✅ Вывод: сортировка — обязательна.
5. Ограничения и защита
Назначение: не позволять клиенту запросить слишком много.
Простыми словами: сервер ставит «потолок».
Аналогия: максимум книг в одной выдаче.
Простыми словами: сервер ставит «потолок».
Аналогия: максимум книг в одной выдаче.
Пример:
limit=20 (max=100)🔎 Как это происходит на практике:
- Клиент пытается запросить
limit=1000. - Сервер ограничивает максимум (например, 100).
- Возвращает данные в пределах лимита.
Характеристики:
- ✅ защищает сервер;
- ✅ прогнозируемая нагрузка;
- ✅ важно для публичного API.
Когда использовать: всегда.
✅ Вывод: лимиты = защита API.
✅ Вывод: лимиты = защита API.
Сравнение пагинации
| Тип | Плюсы | Минусы | Когда |
|---|---|---|---|
| Offset | простая | медленно на больших данных | средние списки |
| Cursor | стабильная | сложнее для клиента | большие базы |
✅ Вывод: выбор зависит от масштаба данных.
Часто спрашивают на собеседованиях
- Зачем нужна сортировка? иначе страницы нестабильны.
- Offset vs Cursor? offset прост, cursor стабильнее.
- Нужен ли total? не всегда, это дорогая операция.
- Какой max limit? зависит от системы, часто 100.
- Почему cursor лучше на больших данных? быстрее и без сдвигов.
✅ Вывод: понимание пагинации = зрелость API.
Типичные ошибки
Ошибка 1: нет сортировки
❌
✅
Почему: без sort записи «прыгают».
/courses?page=2✅
/courses?sort=created_at_desc&page=2Почему: без sort записи «прыгают».
Ошибка 2: слишком большой limit
❌ limit=1000
✅ limit=20, max=100
Почему: нагрузка на сервер.
✅ limit=20, max=100
Почему: нагрузка на сервер.
Ошибка 3: total без необходимости
❌ всегда считать total
✅ считать только при нужном UI
Почему: дорого.
✅ считать только при нужном UI
Почему: дорого.
Ошибка 4: offset для миллиона записей
❌ offset=900000
✅ cursor‑pagination
Почему: offset медленный.
✅ cursor‑pagination
Почему: offset медленный.
Best Practices
- Всегда фиксируйте сортировку.
- Ограничивайте limit.
- Для больших данных используйте cursor.
- Возвращайте next/prev ссылки или курсор.
- Документируйте параметры пагинации.
Заключение
📚 Пагинация делает API лёгким и быстрым.
✅ Правильный тип пагинации спасает производительность.
🚀 Теперь вы умеете выдавать данные порциями, как профессионал.
✅ Правильный тип пагинации спасает производительность.
🚀 Теперь вы умеете выдавать данные порциями, как профессионал.