API-конвенции
Зачем нужно
Документ задаёт обязательные правила HTTP API для всех 7 доменов. Любой backend-сервис экосистемы соответствует этим правилам без исключений.
Базовые правила
- Транспорт: HTTPS.
- Формат: JSON (UTF-8).
- Стиль: REST.
- Префикс:
/api/v2/<namespace>/..., где namespace — один из 7 бизнес-доменов или технический namespaceplatform. Все namespace используют единое мажорное версионированиеv2. - Имена ресурсов в URL: kebab-case, существительные во множественном числе (
/api/v2/lms/courses). - Имена полей в JSON: camelCase.
- Идентификаторы: UUID v4 в виде строки.
- Время: ISO-8601 в UTC, с суффиксом
Z. - Деньги: строка с двумя знаками после точки + поле
currency(ISO 4217), например{"amount":"1990.00","currency":"RUB"}.
Envelope ответа
Успешный одиночный ответ:
{
"data": { ... },
"meta": { "requestId": "..." }
}
Ответ списка:
{
"data": [ ... ],
"meta": {
"requestId": "...",
"page": 1,
"perPage": 50,
"total": 1234,
"cursor": "..."
}
}
Ответ ошибки:
{
"error": {
"code": "...",
"message": "...",
"details": [ ... ]
},
"meta": { "requestId": "..." }
}
requestId совпадает с заголовком X-Request-Id и используется для корреляции в логах и трассировке.
HTTP-методы
| Метод | Назначение |
|---|---|
GET | чтение, идемпотентен |
POST | создание или операция, не выражаемая через PUT/PATCH |
PUT | полная замена ресурса (использ уется редко) |
PATCH | частичное обновление |
DELETE | удаление или soft delete |
Коды ответов
| Код | Когда |
|---|---|
| 200 | успешное чтение или операция |
| 201 | ресурс создан, возвращается тело и Location |
| 202 | операция принята к асинхронной обработке |
| 204 | успешно, тело пустое |
| 400 | bad request, валидация |
| 401 | не аутентифицирован |
| 403 | нет прав |
| 404 | ресурс не найден |
| 409 | конфликт (idempotency, optimistic locking, business conflict) |
| 410 | gone (deprecated endpoint) |
| 422 | бизнес-ошибка валидации |
| 429 | rate limit |
| 500 | внутренняя ошибка |
| 503 | сервис недоступен |
Каталог ошибок
Все коды ошибок строятся как <domain>.<entity>.<reason> или platform.<reason>. Примеры:
platform.validation_failedplatform.unauthorizedplatform.forbiddenplatform.not_foundplatform.conflictplatform.rate_limitedidentity.user.email_takencrm.invoice.already_paidlms.enrollment.entitlement_invalid
Каждый домен ведёт каталог своих ошибок в domains/<name>/api-contracts.md.
Реестр endpoints и contract coverage
domains/<name>/api-map.mdявляется canonical endpoint registry: каждый endpoint домена фиксируется там один раз с методом, путём, permission/caller и назначением.domains/<name>/api-contracts.mdне обязан дублировать полный request/response DTO для каждой строки registry. Он фиксирует общие DTO, envelope, pagination, idempotency, errors и endpoint-specific DTO для неочевидных, интеграционных, публичных или бизнес-критичных команд.- Полное покрытие registry достигается через
Endpoint coveragetable вapi-contracts.md: каждая группа endpoints изapi-map.mdдолжна ссылаться на DTO-секцию вapi-contracts.mdили на профильныйfeatures/*.md. - Если detailed DTO намеренно не расписывается, coverage row должен прямо указывать применяемые общие правила и доменный DTO/feature doc; placeholders вместо источника контракта не допускаются.
Пагинация
Поддерживаются два режима, выбор фиксируется в api-map.md домена:
Page-based
GET /api/v2/lms/courses?page=2&perPage=50
meta.total обязателен.
Cursor-based
GET /api/v2/lms/activity-attempts?cursor=eyJ...&perPage=100
meta.cursor указывает следующий курсор.
perPage по умолчанию 25, максимум 200.
Сортировка и фильтрация
- Сортировка:
?sort=fieldили?sort=-field(минус — desc). Несколько полей через запятую. - Фильтрация:
?filter[<field>]=<value>или?<field>=<value>для простых случаев. Сложные фильтры — POST на/search.
Идемпотентность
Все небезопасные операции (POST, PATCH, DELETE с побочными эффектами вроде платежа) должны принимать заголовок Idempotency-Key. Серве р сохраняет ответ на этот ключ на 24 часа и при повторном запросе возвращает тот же ответ. Подробности в data-baseline.md.
Optimistic concurrency
Для ресурсов с возможным конкурентным изменением — заголовки If-Match: <etag> и ответ ETag. Конфликт — 409 с кодом platform.optimistic_lock_failed.
Заголовки
Обязательные:
Authorization: Bearer <access_token>(для защищённых эндпоинтов);X-Request-Id(если не передан — генерируется сервером);X-Actor-Contextтребуется только для non-personal контекстов ребёнка/семьи/организации/команды/админа; если заголовок отсутствует, сервер трактует запрос какpersonalcontext (описано вauth-integration.md);Idempotency-Keyдля небезопасных операций;Accept-Languageдля локали ответа;If-Match/ETagгде применимо;Content-Type: application/jsonдля тел.
Версионирование
- Мажорная версия — в URL (
v2). - Поломочные изменения — новая мажорная версия.
- Аддитивные изменения внутри мажорной версии разрешены без флагов.
- Удаление поля = поломочное изменение.
Депрекация: 6 месяцев минимум, эндпоинт возвращает заголовок Deprecation: true и Sunset: <date>. После сроков — 410.
Rate limiting
- Глобальный лимит на токен и IP описан в
security-baseline.md. - Локальные лимиты доменов описаны в
domains/<name>/security.md.
Health checks
Каждый сервис обязан выставлять:
GET /health/live— процесс жив;GET /health/ready— готов принимать трафик;GET /health/info— версия и build info.
OpenAPI
Каждый сервис генерирует и публикует OpenAPI 3.1 схему по адресу /api/v2/<namespace>/openapi.json. Схема собирается из Zod-типов через NestJS интеграцию.
Запрещено
- Возвращать данные без envelope.
- Изобретать собственный формат ошибок.
- Использовать snake_case в JSON.
- Передавать секреты в query string.
- Использовать сессионные cookies для public API; cookies используются только для frontend-сессий identity (см.
auth-integration.md). - Версионировать через заголовок без мажорной версии в URL.