REST API Design с помощью AI: принципы, промпты и OpenAPI-спецификация
Что такое проектирование REST API с помощью AI?
Проектирование REST API с помощью AI — это процесс использования LLM для генерации OpenAPI 3.1-спецификаций, валидации naming conventions, построения каталогов ошибок и формирования контрактов пагинации на основе структурированного описания домена и архитектурных ограничений. Подход важен, потому что ручное написание OpenAPI YAML для 30+ эндпоинтов занимает часы и вносит несоответствия, стоящие фронтенд-командам времени на отладку. Ключевое разграничение: AI убирает механическую работу (YAML, примеры, проверка имён), архитектурные решения (стратегия версионирования, формат ошибок, идемпотентность) остаются за инженером.
TL;DR
- -OpenAPI-спецификация, сгенерированная по правильному промпту, автоматически порождает 4 артефакта: TypeScript-типы (openapi-typescript), типизированный клиент (openapi-fetch/orval), middleware валидации запросов на бэкенде и mock-сервер (Prism).
- -3-этапный prompt chaining (базовая спецификация → улучшения → валидационное ревью) даёт production-ready спецификацию за 15–20 минут против нескольких часов ручного YAML.
- -400 vs 422 — критическое различие: 400 = синтаксически невалидный запрос (битый JSON); 422 = синтаксически корректный, но семантически неверный (нарушение бизнес-правила) — фронтенд обрабатывает их по-разному.
- -Cursor-based пагинация стабильна при добавлении новых записей (нет дублей при сдвиге страниц); offset-based проще в реализации, но ломается когда записи добавляются между загрузками страниц.
- -URL-based версионирование (/api/v1/) — правильный выбор по умолчанию для большинства проектов; header-based версионирование чище теоретически, но нетестируемо в браузере и сложнее в документировании.
Плохой API — одна из главных причин срыва сроков на фронтенде. Не баги, не перформанс. Непоследовательные названия эндпоинтов, непредсказуемые ответы на ошибки, отсутствие документации. Один неудачный контракт между бэкендом и фронтендом стоит десятки часов на переделку обеих сторон.
AI меняет процесс проектирования API. Не заменяет архитектора, а ускоряет рутину: генерация OpenAPI-спецификации, проверка naming conventions, моделирование error responses. При правильных промптах LLM выдаёт спецификацию, которую фронтенд-разработчик читает без вопросов.
Дальше разберём полный цикл: от принципов дизайна до готовой OpenAPI-спецификации, сгенерированной с помощью AI. Каждый шаг с конкретным промптом и результатом.
Принципы REST API Design, которые экономят время
Прежде чем открывать чат с AI, нужно зафиксировать правила. LLM генерирует качественные спецификации только при чётких ограничениях. Без них получается каша из разных стилей именования и несогласованных ответов.
Ресурсы, а не действия. URL описывает существительное, HTTP-метод описывает действие. /users + GET вместо /getUsers. /orders/{id} + DELETE вместо /deleteOrder. Правило кажется очевидным, но AI без явного указания часто генерирует RPC-стиль: /createUser, /updateOrder.
Множественное число для коллекций. /users, /products, /orders. Единственное число допустимо только для singleton-ресурсов типа /users/{id}/profile.
Вложенность не глубже двух уровней. /users/{userId}/orders допустимо. /users/{userId}/orders/{orderId}/items/{itemId}/reviews избыточно. Глубокая вложенность усложняет клиентский код и создаёт проблемы с кэшированием. Лучше вынести в отдельный ресурс: /order-items/{itemId}/reviews.
Консистентный формат ответов. Каждый эндпоинт возвращает данные в одинаковой обёртке. Фронтенд-разработчик не должен гадать, придёт { data: [...] } или голый массив. Один формат для успеха, один для ошибки.
Идемпотентность PUT и DELETE. Повторный вызов PUT /users/123 с теми же данными возвращает тот же результат. Повторный DELETE /users/123 возвращает 204 или 404, но не создаёт побочных эффектов. Это критично для retry-логики на фронтенде и в circuit breaker паттернах.
Naming Conventions: как AI помогает сохранить единообразие
Naming conventions определяют, будет ли API читаемым через полгода. В проекте из 50+ эндпоинтов ручное соблюдение единообразия практически невозможно. Один разработчик пишет userId, другой user_id, третий UserID. Выбор между одним API в монолите и множеством API в сервисах - отдельный вопрос, для которого есть сравнение монолита и микросервисов.
AI решает эту задачу через валидацию. Промпт для проверки naming conventions:
Проанализируй следующий список эндпоинтов REST API.
Проверь на соответствие правилам:
- URL: kebab-case для составных слов (/order-items, не /orderItems)
- Query parameters: camelCase (pageSize, sortBy)
- Request/Response body: camelCase для JSON-полей
- Path parameters: camelCase ({userId}, не {user_id})
- Коллекции: множественное число
- Вложенность: не глубже 2 уровней
Для каждого нарушения укажи: эндпоинт, правило, текущий вариант, исправленный вариант.
Эндпоинты:
[вставить список]
Результат: таблица с конкретными исправлениями.
Для генерации новых эндпоинтов по доменной модели:
Дана доменная модель:
- User (id, email, name, role)
- Project (id, title, ownerId, status)
- Task (id, projectId, assigneeId, title, status, priority)
Сгенерируй список REST-эндпоинтов для CRUD-операций.
Правила:
- Базовый путь: /api/v1
- Только необходимые вложенные ресурсы (1 уровень)
- Для каждого эндпоинта укажи: метод, путь, краткое описание, коды ответов
Формат: таблица Markdown.
AI генерирует полный набор эндпоинтов за секунды. Дальше остаётся проверить бизнес-логику: нужен ли PATCH /tasks/{id}/status как отдельный эндпоинт или достаточно PATCH /tasks/{id}.
Versioning стратегии для REST API
Три подхода к версионированию. Каждый с компромиссами.
URL-based: /api/v1/users. Самый распространённый. Прост в реализации, прост для фронтенда. Минус: при смене версии меняются все URL. Если API публичный, старые версии придётся поддерживать годами.
Header-based: Accept: application/vnd.api.v2+json. URL остаётся чистым. Версия передаётся в заголовке. Минус: сложнее тестировать (нельзя просто открыть URL в браузере), сложнее документировать.
Query parameter: /api/users?version=2. URL остаётся стабильным, версия явная. Минус: загрязняет query parameters, конфликтует с кэшированием по URL.
Промпт для выбора стратегии с учётом контекста проекта:
Контекст:
- Внутренний API для мобильного приложения и веб-клиента
- 3 команды-потребителя
- Релиз-цикл: каждые 2 недели
- Планируется публичный API через 6 месяцев
Сравни три стратегии версионирования REST API (URL path, header, query param).
Для каждой: плюсы, минусы, пример.
Дай рекомендацию с обоснованием для описанного контекста.
Для большинства проектов URL-based versioning остаётся оптимальным. AI помогает не с выбором (он почти всегда одинаков), а с планированием миграции между версиями и генерацией deprecation headers.
Error Handling: единый формат ошибок через AI
Ошибки API определяют опыт фронтенд-разработчика больше, чем успешные ответы. Когда что-то ломается, разработчик открывает DevTools и видит ответ. Если там 500 Internal Server Error без деталей, отладка превращается в детективную историю.
Формат ошибок RFC 9457 (Problem Details for HTTP APIs) решает эту проблему:
{
"type": "https://api.example.com/errors/validation",
"title": "Validation Error",
"status": 422,
"detail": "Request body contains invalid fields",
"instance": "/api/v1/users",
"errors": [
{
"field": "email",
"message": "Must be a valid email address",
"code": "INVALID_FORMAT"
},
{
"field": "name",
"message": "Must be between 2 and 100 characters",
"code": "INVALID_LENGTH"
}
]
}
Промпт для генерации полного каталога ошибок:
Сгенерируй каталог ошибок для REST API управления проектами.
Домен: Users, Projects, Tasks.
Требования:
- Формат: RFC 9457 (Problem Details)
- Категории: validation, authentication, authorization, not_found, conflict, rate_limit, internal
- Для каждой ошибки: type (URI), title, status code, пример detail, error code (UPPER_SNAKE_CASE)
- Коды ошибок уникальны и машиночитаемы
Формат вывода: таблица с колонками: Category, Error Code, Status, Title, Example Detail.
AI генерирует каталог из 20-30 ошибок, покрывающий основные сценарии. После генерации каталог становится контрактом. Фронтенд использует error.code для программной обработки (INVALID_FORMAT показывает подсказку у поля), error.detail — для отладки.
Типичные коды и когда их использовать:
| Status | Когда | Пример |
|---|---|---|
| 400 | Невалидный JSON, отсутствуют обязательные поля | Тело запроса не парсится |
| 401 | Отсутствует или невалидный токен | Expired JWT |
| 403 | Токен валиден, но нет прав | Пользователь не owner проекта |
| 404 | Ресурс не найден | Нет проекта с таким ID |
| 409 | Конфликт состояния | Email уже зарегистрирован |
| 422 | Валидация бизнес-правил | Нельзя удалить проект с активными задачами |
| 429 | Rate limit | Превышен лимит запросов |
Частая ошибка: путать 400 и 422. 400 означает синтаксически невалидный запрос (битый JSON). 422 означает синтаксически валидный, но семантически неверный (email в неправильном формате). Фронтенд обрабатывает их по-разному.
Генерация OpenAPI-спецификации с помощью AI
OpenAPI (Swagger) спецификация превращает описание API из документа в исполняемый контракт. Фронтенд генерирует типы и API-клиент. Бэкенд валидирует запросы. Тестировщик генерирует тест-кейсы.
Ручное написание OpenAPI YAML для 30+ эндпоинтов занимает часы. AI сокращает это до минут. Ключ в правильном промпте.
Шаг 1: базовая спецификация
Сгенерируй OpenAPI 3.1 спецификацию в YAML для REST API управления задачами.
Ресурсы:
- Users: CRUD, поля (id, email, name, role, createdAt, updatedAt)
- Projects: CRUD + list by user, поля (id, title, description, status, ownerId, createdAt)
- Tasks: CRUD + list by project + update status, поля (id, title, description, status, priority, projectId, assigneeId, createdAt, updatedAt)
Требования:
- Базовый путь: /api/v1
- Аутентификация: Bearer JWT
- Пагинация: cursor-based (query params: limit, cursor)
- Формат ошибок: RFC 9457
- Naming: kebab-case в URL, camelCase в JSON body
- Переиспользуемые схемы в components/schemas
- Примеры для каждого эндпоинта (requestBody + responses)
- Теги для группировки по ресурсам
Шаг 2: итеративное улучшение
После первой генерации спецификация требует доработки. AI хорошо справляется с итеративным улучшением, если указать конкретные проблемы:
Улучши сгенерированную OpenAPI-спецификацию:
1. Добавь rate limiting headers в каждый ответ (X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset)
2. Добавь ETag и If-None-Match для GET-эндпоинтов
3. Добавь Link header для пагинации (RFC 8288)
4. Убедись, что все 4xx/5xx ответы используют единую схему ProblemDetails
5. Добавь discriminator для поля status в Task (open, in_progress, done, cancelled)
Шаг 3: валидация
Проверь OpenAPI-спецификацию на:
- Консистентность naming conventions
- Полноту описания ошибок (все эндпоинты должны описывать 400, 401, 403, 500)
- Наличие примеров для всех requestBody и response
- Правильное использование $ref (нет дублирования схем)
- Корректность HTTP-методов (GET не имеет body, DELETE возвращает 204)
Выведи список проблем с номерами строк и предложениями по исправлению.
Три шага превращают черновик в production-ready спецификацию. Весь процесс занимает 15-20 минут вместо нескольких часов.
Pagination, Filtering и Sorting: контракт для фронтенда
Пагинация определяет, насколько удобно фронтенду работать со списками. Два подхода: offset-based и cursor-based.
Offset-based (?page=2&pageSize=20) прост в реализации. Фронтенд показывает номера страниц. Минус: при добавлении новых записей страницы “сдвигаются”. Пользователь на странице 3 видит запись, которую уже видел на странице 2.
Cursor-based (?cursor=eyJpZCI6MTIzfQ&limit=20) стабилен. Курсор указывает на конкретную запись, а не на позицию. Записи не дублируются при добавлении новых. Минус: нельзя показать “страница 5 из 12”. Подходит для бесконечного скролла.
Промпт для генерации query-параметров фильтрации:
Для ресурса Tasks со следующими полями:
- status: enum (open, in_progress, done, cancelled)
- priority: enum (low, medium, high, critical)
- assigneeId: UUID
- projectId: UUID
- createdAt: datetime
- updatedAt: datetime
Сгенерируй набор query-параметров для фильтрации и сортировки.
Правила:
- Фильтры: точное совпадение и диапазоны (для дат)
- Множественные значения через запятую: ?status=open,in_progress
- Сортировка: ?sort=createdAt:desc,priority:asc
- Пагинация: cursor-based
- Формат параметров: camelCase
Выведи таблицу: Parameter, Type, Description, Example.
Результат: готовый контракт. Фронтенд знает точный формат каждого параметра. Бэкенд знает, что парсить.
Промпт для полной генерации API-контракта
Финальный промпт объединяет все принципы. Этот промпт используется в начале проекта для генерации первой версии API-контракта. Дальше он итеративно дорабатывается.
Роль: Senior API Architect.
Задача: спроектировать REST API для [описание домена].
Входные данные:
- Доменная модель: [список сущностей с полями и связями]
- Потребители: [веб-клиент, мобильное приложение, внешние интеграции]
- Нефункциональные требования: [RPS, latency, авторизация]
Выходной формат: OpenAPI 3.1 YAML.
Архитектурные решения:
- Versioning: URL-based (/api/v1/)
- Auth: Bearer JWT + refresh tokens
- Pagination: cursor-based
- Error format: RFC 9457 (Problem Details)
- Naming: kebab-case URLs, camelCase JSON
- Идемпотентность: Idempotency-Key header для POST
Для каждого эндпоинта обязательно:
1. Summary и description
2. Все query/path/header parameters с описанием
3. RequestBody schema с примером
4. Response schemas для 2xx и всех возможных 4xx/5xx
5. Security requirements
6. Tags для группировки
Дополнительные секции:
- components/schemas для всех моделей (с required полями)
- components/securitySchemes
- components/parameters для переиспользуемых параметров (pagination, sorting)
- components/responses для стандартных ошибок
Стиль: production-ready, готов к codegen (openapi-generator).
Этот промпт работает как техническое задание для AI. Чем точнее ограничения, тем меньше итераций потребуется. Подробнее о структурировании контекста для LLM в руководстве по context engineering.
Валидация API Design: чеклист перед передачей фронтенду
Сгенерированную спецификацию стоит проверить перед тем, как отдавать фронтенд-команде. AI помогает и здесь, но финальное решение принимает человек.
Промпт для design review:
Проведи ревью REST API спецификации как Senior Frontend Developer.
Оцени по критериям:
1. Предсказуемость: одинаковые паттерны для одинаковых операций?
2. Самодокументируемость: названия эндпоинтов и полей понятны без описания?
3. Удобство интеграции: можно ли сгенерировать типизированный клиент?
4. Обработка ошибок: достаточно информации для показа пользователю?
5. Пагинация: удобно ли реализовать infinite scroll и table pagination?
6. Фильтрация: покрывает ли основные UI-сценарии?
7. Кэширование: есть ли ETag, Cache-Control?
Для каждого критерия: оценка (OK / Needs improvement), конкретное замечание, пример исправления.
Чеклист для ручной проверки:
- Все эндпоинты следуют одному стилю именования
- HTTP-методы соответствуют семантике (GET не меняет состояние)
- Каждый POST возвращает созданный ресурс с
201 CreatedиLocationheader - PUT и PATCH различаются: PUT заменяет ресурс целиком, PATCH обновляет отдельные поля
- DELETE возвращает 204 (без тела) или 200 (с телом удалённого ресурса)
- Все списки поддерживают пагинацию
- Query parameters для фильтрации задокументированы с допустимыми значениями
- Ответы на ошибки включают machine-readable код (не только текст)
- Security scheme применён ко всем эндпоинтам (кроме public)
- Нет circular references в schemas
Автоматизация: от спецификации к коду
OpenAPI-спецификация, сгенерированная с помощью AI, становится отправной точкой для автоматизации.
Генерация типов для фронтенда. openapi-typescript читает YAML и создаёт TypeScript-типы. Фронтенд-разработчик получает автокомплит для каждого поля ответа.
npx openapi-typescript ./openapi.yaml -o ./src/api/types.ts
Генерация API-клиента. openapi-fetch или orval создают типизированный клиент с валидацией запросов на этапе компиляции.
Валидация на бэкенде. Middleware сверяет входящие запросы и исходящие ответы с OpenAPI-схемой. Любое отклонение от контракта обнаруживается до попадания в продакшен.
Mock-сервер. prism от Stoplight поднимает mock API из OpenAPI-файла. Фронтенд начинает интеграцию до готовности бэкенда.
npx @stoplight/prism-cli mock openapi.yaml
Одна спецификация генерирует типы, клиент, валидацию и мок-сервер. Разработка фронтенда и бэкенда идёт параллельно без блокировок.
Итоги: API Design как инженерная дисциплина
REST API design с AI-ассистентом строится на чёткой последовательности:
- Зафиксировать принципы и naming conventions до начала генерации
- Сгенерировать базовую OpenAPI-спецификацию через структурированный промпт
- Итеративно улучшить: error handling, pagination, headers
- Провалидировать глазами фронтенд-разработчика (или AI в роли фронтендера)
- Автоматизировать: типы, клиент, mock-сервер из единой спецификации
AI не заменяет знание принципов API design. Он убирает рутину: набор YAML, проверку naming, генерацию примеров. Архитектурные решения (cursor vs offset, URL vs header versioning, формат ошибок) по-прежнему принимает инженер - и их стоит фиксировать как Architecture Decision Records, чтобы обоснование переживало смену команды.
Спецификация, сгенерированная по описанному процессу, становится единым источником правды. Тот же паттерн структурированного промптинга работает для генерации схемы базы данных из PRD - другой артефакт, та же дисциплина фиксации ограничений до генерации. Фронтенд знает точный формат ответа. Бэкенд знает, что валидировать. Тестировщик знает, что проверять. Один файл вместо десятков сообщений в чате с вопросом “а что вернёт этот эндпоинт”.
Нужна помощь с проектированием API? Я помогаю стартапам внедрять AI-решения и строить продукты — belov.works.
Часто задаваемые вопросы
Как версионировать REST API без поломки существующих клиентов при изменении схемы ответа?
Sunset и примечание в OpenAPI-спецификации, затем удалить его в следующей мажорной версии после объявленной даты sunset. Инструменты вроде openapi-diff позволяют автоматически выявлять breaking changes в CI до слияния PR.
Когда API должен возвращать 200 с ошибкой в теле ответа вместо корректного 4xx-статуса?
Как правильно реализовать загрузку файлов в REST API, спроектированном с OpenAPI?
multipart/form-data для загрузки файлов, не application/json. В OpenAPI 3.1 определите requestBody с content: multipart/form-data и схемой с полем format: binary для файла. Для больших файлов (свыше 5 МБ) рассмотрите двухшаговый паттерн загрузки: клиент запрашивает у API presigned URL для загрузки, загружает файл напрямую в объектное хранилище (S3, GCS) через этот URL, затем уведомляет API о ссылке на загруженный объект. Это исключает прохождение больших бинарных данных через серверы приложения и API-шлюз, повышая надёжность и снижая нагрузку на инфраструктуру.