Пагінація
Ендпоінти списків (GET /v1/vms, GET /v1/snapshots тощо) розбивають результати на сторінки за непрозорими курсорами, а не за числовими зсувами. Пагінація за курсором — правильний вибір за замовчуванням для списків ресурсів, які змінюються, поки ви гортаєте сторінки: вона повертає кожен елемент рівно один раз, навіть якщо між запитами сторінок рядки додаються чи видаляються.
Формат
Два параметри query на кожному ендпоінті списку:
limit— розмір сторінки. За замовчуванням 50, максимум 200. Понад 200 запит не проходить валідацію:422validation_error(Помилки).cursor— непрозорий вказівник на наступну сторінку. У першому запиті не передавайте його.
Кожна відповідь зі списком містить:
{
"items": [ /* ... */ ],
"pagination": {
"next_cursor": "eyJpZCI6InZtXzAxSEc3Li4uIn0=",
"total_count": null
}
}Коли next_cursor дорівнює null, ви дійшли до останньої сторінки.
Обхід сторінок
async function listAllVms(): Promise<VM[]> {
const all: VM[] = []
let cursor: string | undefined
do {
const url = new URL('https://api.nimbusnexus.net/v1/vms')
url.searchParams.set('limit', '200')
if (cursor) url.searchParams.set('cursor', cursor)
const res = await fetch(url, { headers: auth })
const { items, pagination } = await res.json()
all.push(...items)
cursor = pagination.next_cursor ?? undefined
} while (cursor)
return all
}Три правила:
- Курсори непрозорі. Не намагайтеся їх розбирати чи складати самі. Вони кодують стан сортування й фільтрів з вашого початкового запиту, тому курсор від одного запиту не працює в іншому.
- Не змінюйте фільтри посеред пагінації. Якщо ви почнете з
?status=running, а для сторінки 2 додасте?region=us-east-1, поведінка буде невизначеною. Коли фільтри змінюються, починайте спочатку (без курсора). - Зупиняйтеся, коли
next_cursorдорівнює null. Не намагайтеся гортати далі «про всяк випадок» — курсор є єдиним достовірним сигналом кінця списку.
Чому курсори, а не ?page=2&per_page=50
Пагінація за зсувом ламається у двох реальних сценаріях:
Вставки під час пагінації. Якщо ви отримали сторінку 1 (елементи 1–50), потім хтось створив нову VM, а тоді ви отримали сторінку 2 (елементи 51–100), то побачите елемент 50 двічі (тепер він на позиції 51) і так і не побачите нового елемента. Курсори фіксують, «де ви були», — наступна сторінка починається після того місця, де ви справді були, а не з абсолютного зсуву.
Видалення під час пагінації. Та сама проблема навпаки: якщо між запитами сторінок VM видаляють, клієнт із пагінацією за зсувом пропускає один елемент. Клієнти з пагінацією за курсором — ні.
Ці граничні випадки важливі за будь-якого нетривіального масштабу. Ми за замовчуванням використовуємо пагінацію за курсором, щоб вони вам не дошкуляли.
total_count
Поле total_count у pagination на більшості ендпоінтів дорівнює null — так задумано. Підрахунок усіх елементів у списку зі сторінками — дорогий запит, який стає дедалі менш корисним зі зростанням N («у вас 14 328 VM в усіх ваших проєктах» — і що з цим робити?). Якщо total_count є, його описано на сторінці довідника цього ендпоінта; якщо його немає, не покладайтеся на нього.
Якщо вам справді потрібна точна кількість, пройдіть усі сторінки до кінця й порахуйте, що отримали.
Порядок сортування
Ендпоінти списків мають сортування за замовчуванням (зазвичай created_at desc, спершу найновіші), описане для кожного ендпоінта окремо. Деякі ендпоінти приймають ?sort=, щоб його змінити; на сторінці довідника перелічено допустимі значення.
Курсор кодує сортування, тому зміна ?sort= між запитами сторінок — один із випадків «невизначеної поведінки»: змінивши сортування, починайте спочатку.
Фільтри
Кожен ендпоінт списку приймає кілька стандартних параметрів фільтрації:
created_after/created_before— timestamp-и в RFC 3339updated_after/updated_before— timestamp-и в RFC 3339- Фільтри, специфічні для ресурсу (напр.
?region=us-east-1&state=runningдля VM)
Фільтри комбінуються: відповідь — це AND усіх фільтрів. Які фільтри приймає ресурс, описано на його сторінці довідника.
Коли вам справді потрібні всі елементи
Викликати список із пагінацією в щільному циклі, щоб перебрати всі ресурси, — нормально для разової роботи, але дорого для демонів, які роблять це постійно. Є два кращі патерни:
- Вебхуки. Підпишіться на події
resource.created/resource.deletedі підтримуйте власний індекс. Див. сторінку Вебхуки платформи. - Ендпоінти масового експорту. Для деяких ресурсів (снапшоти, бекапи, журнали аудиту) є окремий ендпоінт експорту, який віддає весь набір потоком в одній відповіді. Там, де такі ендпоінти є, їх описано на сторінці довідника ресурсу.
Патерн пагінації призначений для інтерактивного використання (таблиця в дашборді, команда list у CLI). Для безперервної синхронізації витрати на пагінацію переважають, і правильна відповідь — вебхуки.
Що далі
- Угоди — решта формату запиту (коди статусу, помилки, ідемпотентність).
- Вебхуки платформи — push-альтернатива для безперервної синхронізації.
- Сторінка довідника будь-якого ендпоінта списку — фільтри й варіанти сортування цього ендпоінта.