Версионирование, пагинация и ответы N+1 — Примеры
Пример 1 — Размер страницы, который обеспечивает сервер
Коллекция заказов возвращает всё, что есть у аккаунта. Клиент начал просить очень большую страницу. Дайте коллекции максимум, который обеспечивает сервер, упорядочение и способ дойти до следующей страницы, — и покажите запрос и ответ так, как их увидит клиент.
GET /orders?limit=5000
200 OK
[ ... 41 208 заказов в одном теле ... ] (иллюстративно)
Решение
GET /orders?limit=5000&order=placed_at,desc
(сервер обрезает limit до 100)
200 OK
{
"items": [ ... 100 заказов, сначала новые ... ],
"next": "/orders?limit=100&cursor=page-3"
}
Максимум принадлежит серверу, поэтому запрос на 5000 обрезается, а не принимается на веру, и ни один вызов не может исчерпать память. Упорядочение указано потому, что курсор осмыслен только относительно него, а переход по next дважды возвращает каждый заказ ровно один раз, даже пока прибывают новые заказы, — чего пагинация со смещением на движущейся коллекции не обещает. Однако обычно ошибаются иначе: limit проверяют отклонением всего запроса, что ломает клиента, который лишь немного переоценил, или оставляют без ограничения вовсе.
Пример 2 — Два запроса вместо пятидесяти одного
В списке заказов теперь показывается имя каждого клиента, и эндпоинт выдаёт один запрос на страницу и ещё по одному на заказ; журнал ниже — со страницы в пятьдесят, а сделать число запросов нужно независимым от числа возвращаемых строк.
GET /orders?page=1 (50 заказов, иллюстративно)
select * from orders order by placed_at desc limit 50;
select * from customers where id = 7; ... 50 раз, по одному на заказ
число запросов: 51
Решение
select * from orders order by placed_at desc limit 50;
select * from customers where id in (7, 9, 12, ...); один запрос на страницу
число запросов: 2
Оба оператора ограничены страницей, поэтому стоимость перестаёт расти с результатом. Правило, которое это сохраняет, — форма ответа: коллекция несёт идентификаторы, а связанная коллекция, например позиции заказа, — собственный адрес. Обычно ошибаются иначе: собирают ответ элемент за элементом, позволяя каждому получить свою связанную запись, из-за чего запрос на элемент возвращается на первом же пути в коде, который касается этого поля.