Читать книгу Full stack Developer - Группа авторов - Страница 10

Раздел II. Продукт и требования, единые для всех реализаций.
Глава 8. API Contract (OpenAPI) – пишем до кода

Оглавление

Эта глава – про дисциплину, которая экономит недели: сначала описываем API как договор, а потом реализуем.

OpenAPI – это формат, который позволяет:

– задокументировать endpoints,

– описать схемы данных,

– зафиксировать ошибки,

– автоматически генерировать документацию и клиентов (если нужно).

Мы не будем вставлять огромный YAML на 30 страниц. Вместо этого зафиксируем структуру контракта, модели и правила, а также ключевые endpoints.

8.1. Основные принципы контракта

1) Стабильные модели ошибок (один формат на весь API).

2) Понятные коды ответа (не “всегда 200”).

3) Пагинация единым способом для всех списков.

4) Аутентификация единым способом.

5) Версионирование с первого дня.

И ещё правило, которое спасает нервы:

> Если вы не можете объяснить endpoint одной фразой – скорее всего, он делает слишком много.

8.2. Auth model (модель аутентификации)

Для простоты (и реальности) выбираем:

– Bearer token в заголовке Authorization: Bearer <token>

Где токен берётся:

– из POST /auth/login (и, возможно, POST /auth/register сразу возвращает токен)

В OpenAPI это описывается как security scheme типа HTTP bearer.

Минимальные endpoints auth

– POST /auth/register

– POST /auth/login

– POST /auth/logout (опционально; зависит от того, храним ли сессии на сервере)

– GET /me (получить профиль текущего пользователя)

8.3. Error model (единая модель ошибок)

Самая частая боль API – когда ошибки везде разные. Мы сделаем единый формат.

Предлагаемая модель:

json

{

"error": {

"code": "validation_error",

"message": "Invalid request",

"details": [

{ "field": "email", "message": "Invalid format" }

],

"request_id": "req_123"

}

}

Где:

– code – машинно-обрабатываемый код (snake_case)

– message – коротко для человека

– details – массив деталей (опционально)

– request_id – чтобы найти запрос в логах

Типовые коды ошибок

– validation_error → HTTP 400

– unauthorized → 401

– forbidden → 403

– not_found → 404

– conflict → 409

– rate_limited → 429

– internal_error → 500

Важно: для 500 мы не раскрываем внутренности. Логи – для нас, клиенту – “internal_error”.

8.4. Pagination model (модель пагинации)

Мы выбрали cursor pagination для основных списков.

Запрос

Параметры:

– limit (по умолчанию 20, максимум например 100)

– cursor (опционально)

Пример:

GET /tasks?limit=20&cursor=eyJjcmVhdGVkX2F0IjoiLi4uIiwiaWQiOiIuLi4ifQ==

Ответ

Единый формат списка:

json

{

"items": [ … ],

"page": {

"next_cursor": "....",

"has_more": true

}

}

Правила:

– если has_more=false, next_cursor может быть null

– курсор непрозрачный для клиента (он не обязан понимать содержимое)

Если для некоторых endpoint’ов нужен offset – лучше не смешивать. Но если уж смешали, делайте разные endpoint’ы или разные модели ответа, чтобы клиент не гадал.

8.5. Versioning (версионирование)

Варианты:

– через путь: /api/v1/…

– через заголовок: Accept: application/vnd.taskflow.v1+json

Для простоты и ясности берём версию в пути:

– /api/v1

Почему:

– проще дебажить,

– проще проксировать,

– проще объяснить.

Правило:

– ломающее изменение – новая версия (/v2)

– не ломающее – расширяем текущую версию (добавляем поля, новые endpoints)

8.6. Endpoints: фиксируем основной набор

Ниже – список endpoint’ов, который покрывает домен из главы 6. Формат: метод, путь, смысл, основные ответы.

8.6.1. Auth / User

POST /api/v1/auth/register

Создать пользователя.

Request:

– email

– password

– name (опционально)

Responses:

– 201 → создан пользователь (+ возможно токен)

– 400 validation_error

– 409 conflict (email занят)

– 429 rate_limited

POST /api/v1/auth/login

Логин.

Request:

– email

– password

Responses:

– 200 → токен

– 400 validation_error

– 401 unauthorized

– 429 rate_limited

GET /api/v1/me

Текущий пользователь.

Responses:

– 200 user profile

– 401 unauthorized

8.6.2. Workspaces и участники

POST /api/v1/workspaces

Создать workspace.

Headers:

– Idempotency-Key (рекомендуется)

Responses:

– 201 workspace

– 401 unauthorized

– 400 validation_error

GET /api/v1/workspaces

Список workspace, где пользователь состоит.

Responses:

– 200 list (можно без пагинации, если их мало, но лучше с limit/cursor)

GET /api/v1/workspaces/{workspaceId}

Получить workspace.

Responses:

– 200

– 403 forbidden (если нет доступа)

– 404 not_found (можно вернуть 404 вместо 403, чтобы не “палить” существование)

POST /api/v1/workspaces/{workspaceId}/members

Добавить участника (owner/admin).

Request:

– user_email или user_id

– role (admin/member)

Responses:

– 201

– 403

– 404

– 409 (уже участник)

PATCH /api/v1/workspaces/{workspaceId}/members/{userId}

Изменить роль.

Responses:

– 200

– 403

– 409 (например, нельзя понизить owner “в никуда”)

DELETE /api/v1/workspaces/{workspaceId}/members/{userId}

Удалить участника.

Responses:

– 204

– 403

8.6.3. Projects

POST /api/v1/workspaces/{workspaceId}/projects

Создать проект.

Headers:

– Idempotency-Key (рекомендуется)

Responses:

– 201

– 403

– 400

GET /api/v1/workspaces/{workspaceId}/projects

Список проектов (с фильтром status=active|archived).

Responses:

– 200 paginated list

GET /api/v1/projects/{projectId}

Получить проект.

Responses:

– 200

– 403/404

PATCH /api/v1/projects/{projectId}

Обновить проект (name/description/status).

Responses:

– 200

– 400

– 403

8.6.4. Tasks

POST /api/v1/projects/{projectId}/tasks

Создать задачу в проекте.

Headers:

– Idempotency-Key (рекомендуется)

Request:

– title (required)

– description (optional)

– assignee_user_id (optional)

– priority (optional)

– due_date (optional)

– labels (optional: массив label_id)

Responses:

– 201 task

– 400 validation_error

– 403 forbidden

– 409 conflict (если идемпотентность конфликтует)

GET /api/v1/tasks/{taskId}

Получить задачу.

Responses:

– 200

– 403/404

PATCH /api/v1/tasks/{taskId}

Обновить задачу (частично).

Responses:

– 200

– 400

– 403

DELETE /api/v1/tasks/{taskId}

Удалить (или архивировать) задачу.

Responses:

– 204

– 403

GET /api/v1/workspaces/{workspaceId}/tasks

Список задач в workspace с поиском/фильтрами.

Query params (примерный набор):

– q – поиск по тексту

– project_id

– status

– assignee_user_id

– label_id

– sort (например created_at, updated_at, due_date)

– order (asc|desc)

– limit, cursor

Responses:

– 200 paginated list

8.6.5. Comments

POST /api/v1/tasks/{taskId}/comments

Добавить комментарий.

Headers:

– Idempotency-Key (можно, но не обязательно; полезно)

Request:

– body

Responses:

– 201

– 400

– 403

GET /api/v1/tasks/{taskId}/comments

Список комментариев (pagination).

Responses:

– 200

DELETE /api/v1/comments/{commentId}

Удалить комментарий (если разрешено правилами).

Responses:

– 204

– 403

8.6.6. Labels

POST /api/v1/workspaces/{workspaceId}/labels

Создать метку.

Responses:

– 201

– 400

– 403

– 409 (если имя метки уникально в workspace)

GET /api/v1/workspaces/{workspaceId}/labels

Список меток.

Responses:

– 200 (можно без пагинации, но лучше с limit/cursor)

8.6.7. Webhooks / Notifications (минимальный контракт)

Если делаем webhooks:

– POST /api/v1/workspaces/{workspaceId}/webhooks – создать подписку

– GET /api/v1/workspaces/{workspaceId}/webhooks – список

– DELETE /api/v1/webhooks/{webhookId} – удалить

Модель webhook:

– url

– events (например task.created, comment.created)

– secret (для подписи)

– is_active

Для email-уведомлений в учебной версии часто достаточно “внутренней отправки” без внешнего API. Но события всё равно должны быть в аудит/логах.

8.7. Коды ответов и “мелкая гигиена API”

Несколько правил, которые повышают доверие к API:

– POST создание → 201 Created (+ тело созданного ресурса)

– DELETE успешный → 204 No Content

– PATCH успешный → 200 OK (+ обновлённый ресурс)

– GET список → 200 OK + { items, page }

И ещё:

– даты/время – в ISO 8601 (2026-01-01T12:34:56Z)

– идентификаторы – строки (часто удобнее и переносимее)

– не возвращайте поля, которые клиент не должен видеть (пароли, секреты)

8.8. Что можно установить, чтобы удобно работать с OpenAPI

– Swagger UI или любая UI-обёртка для просмотра спецификации

– Postman/Insomnia – импортировать спецификацию и тестировать запросы

– Редактор YAML/JSON с подсветкой схем (любой нормальный IDE/редактор справится)

8.9. Мини-итог главы

Мы превратили требования продукта в набор понятных договорённостей:

– endpoints,

– модель ошибок,

– модель пагинации,

– модель аутентификации,

– версия API.

Теперь можно переходить к реализации на любом языке, не споря “как лучше назвать поле” на каждом шаге – всё уже зафиксировано контрактом.

Full stack Developer

Подняться наверх