Проектирование HTTP API — REST-конвенции (ресурсы, методы, статус-коды), пагинация (cursor vs offset), версионирование, идемпотентность (Idempotency-Key), формат ошибок RFC 7807 (problem+json), безопасность и rate limiting. Use при проектировании, ревью или версионировании API и эндпоинтов, выборе кодов ошибок, пагинации, лимитов или формата ответа.
Scanned 9/11/2026
Install to Claude Code
npx -y skills add Vitammiin/agent-vorcl-flow --skill api-design --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Api Design?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/vitammiin-api-design)More formats (shields.io, HTML) on the badges page.
---
name: api-design
description: Проектирование HTTP API — REST-конвенции (ресурсы, методы, статус-коды), пагинация (cursor vs offset), версионирование, идемпотентность (Idempotency-Key), формат ошибок RFC 7807 (problem+json), безопасность и rate limiting. Use при проектировании, ревью или версионировании API и эндпоинтов, выборе кодов ошибок, пагинации, лимитов или формата ответа.
---
# Навык: API Design
## REST-конвенции
Ресурсы — существительные во множественном числе; действие выражает HTTP-метод, не URL (`POST /orders`, а не `POST /createOrder`). Вложенность — максимум один уровень (`/users/{id}/orders`), глубже — фильтром (`/orders?userId=`). Действие вне CRUD — суб-ресурсом: `POST /orders/{id}/cancel`.
| Метод | Семантика | Идемпотентен | Успех | Типичные ошибки |
|---|---|---|---|---|
| GET | чтение | ✅ | 200 | 404 |
| POST | создание / действие | ❌ | 201 (+ `Location`) или 200 | 400, 409, 422 |
| PUT | полная замена | ✅ | 200 | 404, 409 |
| PATCH | частичное обновление | ❌ | 200 | 404, 409, 422 |
| DELETE | удаление | ✅ | 204 | 404 |
Статусы ошибок: 400 — синтаксически кривой запрос; 422 — валидный JSON, не прошедший бизнес-валидацию; 401 — не аутентифицирован; 403 — аутентифицирован, но нельзя; 409 — конфликт состояния (дубликат, устаревшая версия); 429 — превышен лимит (+ `Retry-After`).
## Пагинация
| | Offset (`?page=3&limit=20`) | Cursor (`?cursor=xyz&limit=20`) |
|---|---|---|
| Простота | ✅ проще, произвольная страница | сложнее, только «дальше» |
| Стабильность при вставках/удалениях | ❌ дубли и пропуски между страницами | ✅ стабильна |
| Скорость на глубине | ❌ `OFFSET 100000` читает и выбрасывает | ✅ `WHERE (sort_key, id) < cursor` по индексу |
| Когда | админки, маленькие статичные списки | ленты, публичные API, большие/живые данные |
Cursor — непрозрачная строка (base64 от `(sort_key, id)`), клиент её не парсит. Ответ списка — конверт: `{ "data": […], "nextCursor": "…", "hasMore": true }`. Лимит — с дефолтом и максимумом (например 20/100).
## Версионирование
- Ломающее (удаление/переименование поля, смена типа или семантики) — только в новой версии. Добавление опциональных полей — не ломающее, версии не требует.
- Дефолт — версия в пути: `/v1/…` (явно, кэшируемо, просто в роутинге). Альтернатива — заголовок (`Accept: …;version=2`) для чистых URL.
- Клиент — tolerant reader: неизвестные поля ответа игнорирует, тогда добавления безопасны.
- Старую версию не бросай молча: `Deprecation`/`Sunset`-заголовки, срок жизни, заметки по миграции.
## Идемпотентность
- GET/PUT/DELETE идемпотентны по контракту — клиент может безопасно ретраить.
- POST с побочным эффектом (платёж, заказ) — **Idempotency-Key**: клиент шлёт уникальный ключ заголовком; сервер хранит `key → результат` (Redis/БД, TTL ~24ч) и на повтор возвращает сохранённый ответ, не выполняя операцию дважды. Обязателен для денежных операций и любых ретраящихся вызовов (вебхуки, очереди).
- Потребители очередей — идемпотентны всегда: at-least-once означает, что дубли будут.
## Ошибки: RFC 7807 (application/problem+json)
Единый формат всех ошибок API:
```json
{
"type": "https://api.example.com/errors/insufficient-funds",
"title": "Insufficient funds",
"status": 422,
"detail": "Balance 5.00 is less than order total 20.00",
"instance": "/orders/req-7f3a",
"code": "INSUFFICIENT_FUNDS",
"errors": [{ "field": "amount", "message": "…" }]
}
```
- `code` — стабильный машинный код: по нему ветвится клиент; человекочитаемый текст может меняться и локализоваться.
- Валидационные ошибки — списком по полям, все сразу, не по одной.
- Не течь внутренностями: stack trace, SQL, имена таблиц — только в логи; наружу — generic 500 + `instance`/requestId для соотнесения с логами.
## Пример хорошего эндпоинта
```
POST /v1/orders
Authorization: Bearer <token>
Idempotency-Key: 3f2a-…
{ "items": [{ "productId": "p_1", "qty": 2 }] }
201 Created
Location: /v1/orders/ord_9x1
{ "id": "ord_9x1", "status": "pending", "total": { "amount": 4200, "currency": "EUR" }, "createdAt": "2026-08-06T10:00:00Z" }
```
Деньги — минорными единицами + валюта (не float); даты — ISO 8601 в UTC; id — префиксованные строки. Ошибка того же эндпоинта — problem+json с 422 и машинным `code`.
## Безопасность (минимум)
Аутентификация на каждом эндпоинте (Bearer/JWT), авторизация — на уровне ресурса (чужой `orderId` → 403/404), rate limiting per-user/per-key с 429, вход валидируется схемой (zod) до бизнес-логики.
## Углублённо
- REST vs GraphQL vs gRPC: GraphQL — клиенты с разными потребностями в данных; gRPC — внутренняя сервис-сервис связь с жёсткими контрактами; дефолт публичного API — REST.
- Контракты и OpenAPI-покрытие → `$swagger-coverage`.
- Коды и обработка ошибок → `$error-handling`.
- Локализация ответов (i18n) → `$i18n`: контракт ошибок — стабильный машинный `code` + параметры (не готовый переведённый текст), выбор языка по `Accept-Language`/локали пользователя.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!