7 решений в API, которые окупаются годами
Если коротко
- Семь решений ценой в день. Возврат — годы спокойной интеграции.
- Идемпотентность и request-ID — самые дешёвые. Версионирование и аудит — самые благодарные.
- Плюс два решения, которые я бы сделал иначе, если бы пересобирал сейчас.
Minimalist editorial illustration of a tidy interior wall with seven distinct sockets/switches in a neat row, each glowing a different soft shade of indigo. Through a window, a soft rain falls calmly outside. Calm violet-to-indigo palette, no logos, no readable text, 16:9, 1600x900, professional editorial style.
В API всё похоже на проводку в доме. На черновой день решения занимают минуты. На второй год они либо незаметны, либо стоят клиенту трёх выходных.
Ниже — семь решений, которые мы закладывали в шлюз с первой недели. И два, которые я бы сегодня сделал иначе.
1. На тяжёлую операцию — 202, а не 201
Загрузка файла запускает OCR и эмбеддинг. Это секунды, иногда десятки. Если клиент сидит на открытом соединении — он первый умрёт от таймаута, а вы — вторым, от чужих ретраев.
Шлюз отвечает 202, отдаёт ссылку на ресурс задачи и текущий статус. Клиент сам опрашивает — раз в полторы секунды, через простой HTMX-polling. Никаких висящих коннектов, никаких героических WebSocket'ов в первой версии.
2. Idempotency-Key — пять строк, спасающих класс багов
Заголовок Idempotency-Key. Один и тот же ключ — один и тот же ответ, сколько бы раз клиент ни повторил запрос.
Сеть всегда подведёт. Клиент всегда переретраит. Без идемпотентности это означает три счёт-фактуры там, где должна была быть одна.
3. Backpressure через 429 + Retry-After
Очередь раздулась — шлюз отвечает 429 с заголовком Retry-After: 5. Это не отказ. Это контракт: «мы устали, вернись через пять секунд». Клиент видит и не давит.
Альтернатива — копить запросы в памяти и упасть всем вместе. Дешевле признаваться в усталости.
4. Разные двери для человека и для машины
Дашборд — HTTP Basic / сессия. Программные интеграции — X-API-Key. Не пытайтесь скрестить: получится не велосипед, а гибрид с тремя колёсами.
Два дерева ответственности: одно про живого пользователя (с MFA, ролями, сроками сессии), другое про машину (с ротацией ключей, скоупом, лимитами per-key).
5. Версия — в пути, не в заголовке
Когда настанет момент v2, путь будет /v2/documents, а не Accept-Version: 2.
Видно в curl, видно в логах, видно в браузере. v1 живёт рядом, обслуживается параллельно, на неё можно сослаться без танцев с заголовками.
6. Аудит-журнал с первого дня
Каждое модифицирующее действие пишет строку в append-only таблицу: actor, action, resource, request_id, details. Не «добавим, когда придёт проверка», а сразу.
Журнал, написанный задним числом, никогда не догоняет реальную историю. Подробнее — в отдельной заметке.
7. Один X-Request-ID на весь путь
Клиент прислал ID — используем. Не прислал — генерируем. Идёт через очередь во все воркеры. Каждая лог-строка несёт его рядом с сообщением.
Через полгода поддержка превращается из «давайте посмотрим логи, может найдём» в «вот ID, держите всю трассу запроса». Это разница между «час разбираться» и «минута ответить».
Что бы я сделал иначе
Лимиты per-key, а не глобальные. Сейчас все клиенты делят одну норму. На демо это норм, в зрелой системе — нет: один шумный клиент уносит остальных. Тарифные тиры стоят дешевле, когда их закладывают сразу.
OpenAPI как первоклассный артефакт, а не побочный продукт FastAPI. С примерами, версионированием, генерируемыми SDK. Писать интеграцию без человеческой OpenAPI — это тренировка терпения, а не работы.
- Откройте свой API и поставьте крестики напротив семи пунктов. Считайте честно.
- Начните с двух самых дешёвых — Idempotency-Key и X-Request-ID. Час работы, годы экономии.
- Посмотрите OpenAPI в демо ARA на
/docs.