Как проектировать API

Когда разработчик впервые создает API, он обычно думает о том, как передать данные из базы в интерфейс. Но через год поддержки этого кода он осознает, что API — это не просто набор эндпоинтов, а контракт. И если этот контракт составлен плохо, любое изменение в бизнес-логике превращается в кошмар, который «ломает» всех клиентов: от фронтенда на React до мобильных приложений и сторонних интеграций.
В этой статье мы разберем, как проектировать API так, чтобы оно оставалось гибким, понятным и поддерживаемым на протяжении многих лет.
1. Выбор архитектурного стиля: Не всё есть REST
Первая ошибка новичка — слепое следование REST. Да, REST — это стандарт де-факто, но он не является универсальным решением. Прежде чем рисовать схему эндпоинтов, определитесь с задачами.
- REST (Representational State Transfer). Идеален для большинства CRUD-операций. Его сила в кешировании и стандартных HTTP-методах. Но когда данных становится много, вы сталкиваетесь с проблемой overfetching (получаете лишнее) или underfetching (делаете 10 запросов, чтобы собрать одну страницу).
- GraphQL. Спасение для сложных фронтендов. Позволяет клиенту самому определять структуру ответа. Однако он переносит нагрузку на сервер и усложняет кеширование.
- gRPC. Если вам нужно общение между микросервисами с минимальными задержками, забудьте про JSON и переходите на Protocol Buffers. Это бинарный протокол, который работает в разы быстрее.
- WebSockets / Webhooks. Когда данные должны «прилетать» сами, а не по запросу.
Совет: Не пытайтесь скрестить всё в одном. Часто в одной системе живут REST для внешних клиентов и gRPC для внутреннего взаимодействия между сервисами.
2. Ресурсная модель и именование
Если вы выбрали REST, помните: API должно быть ориентировано на ресурсы, а не на действия.
Плохо (RPC-стиль):
-
GET /getUserData?id=123
-
POST /updateUserEmail
-
POST /deleteOrder
Хорошо (Ресурсный стиль):
-
GET /users/{id}
-
PATCH /users/{id}(обновление конкретного поля)
-
DELETE /orders/{id}
Правила «гигиены» именования:
- Существительные вместо глаголов. Ресурс — это объект. Действие определяется HTTP-методом.
- Множественное число. Используйте
/users, а не/user. Это создает единообразие. - Иерархия. Если ресурс принадлежит другому ресурсу, отразите это в пути:
/users/{id}/orders(заказы конкретного пользователя).
3. Проектирование интерфейса: Детали, которые спасают жизнь
Работа с версионированием
Никогда не выпускайте API без версии. Рано или поздно вам придется изменить структуру ответа, и если у вас нет версионирования, вы «уроните» всех клиентов.
-
- Путевое версионирование:
/v1/users— самый прозрачный и популярный метод.
- Путевое версионирование:
-
- Заголовочное версионирование:
Accept: application/vnd.myapi.v1+json. Более элегантно, но сложнее в отладке через браузер.
- Заголовочное версионирование:
Стандартные ответы и коды ошибок
Самая большая боль интегратора — ответ 200 OK с телом {"error": "Something went wrong"}. Это преступление против архитектуры. Используйте HTTP-статусы по назначению:
-
201 Created— после успешного POST-запроса.
-
204 No Content— когда действие выполнено, но возвращать нечего (например, после DELETE).
-
400 Bad Request— ошибка валидации на стороне клиента.
-
401 Unauthorizedvs403 Forbidden— разница между «я не знаю, кто ты» и «я знаю, кто ты, но тебе сюда нельзя».
-
429 Too Many Requests— когда клиент слишком усердно долбится в ваш API.
Важно: В теле ошибки всегда возвращайте машиночитаемый код ошибки (например, USER_NOT_FOUND) и человекопонятное описание.
4. Производительность и защита: Чтобы сервер не «лег»
Проектирование API — это не только про красивые ссылки, но и про выживание системы под нагрузкой.
Пагинация. Никогда не возвращайте список всех записей. GET /orders должен возвращать порцию данных.
-
- Offset-based (
limitиoffset) — просто, но тормозит на больших объемах данных.
- Offset-based (
-
- Cursor-based (
after_id) — работает быстро и стабильно при постоянном добавлении новых записей.
- Cursor-based (
Фильтрация, сортировка и поиск. Вместо создания пяти разных эндпоинтов, используйте параметры запроса: /products?category=electronics&sort=price_asc.
Rate Limiting. Ограничивайте количество запросов в единицу времени. Это защитит вас от DDOS-атак и «бешеных» скриптов клиентов.
Кеширование. Используйте заголовок ETag или Cache-Control. Если данные не менялись, сервер должен вернуть 304 Not Modified, экономя трафик и ресурсы CPU.
5. Безопасность: Где все ошибаются
Безопасность — это не только HTTPS.
-
- Аутентификация: JWT (JSON Web Tokens) — стандарт для stateless-архитектуры. Но помните о проблеме отзыва токенов. Используйте связку
access_token(короткий срок жизни) иrefresh_token(длинный срок жизни).
- Аутентификация: JWT (JSON Web Tokens) — стандарт для stateless-архитектуры. Но помните о проблеме отзыва токенов. Используйте связку
-
- Валидация: Никогда не доверяйте входящим данным. Каждый параметр должен быть проверен на тип, длину и формат. Инъекции через API — классика жанра.
-
- Принцип наименьших привилегий: Клиент должен иметь доступ только к тем полям, которые ему нужны. Не возвращайте весь объект
Userиз базы (включая хеш пароля и внутренние флаги), создайте отдельный DTO (Data Transfer Object) для ответа.
- Принцип наименьших привилегий: Клиент должен иметь доступ только к тем полям, которые ему нужны. Не возвращайте весь объект
6. Документация как часть продукта
API без документации не существует. Если разработчику нужно писать вам в личку, чтобы понять, какой параметр передавать — ваше API спроектировано плохо.
Инструментарий:
-
- OpenAPI (Swagger). Стандарт индустрии. Позволяет не только описывать API, но и генерировать интерактивную песочницу, где можно потыкать запросы.
-
- Postman Collections. Отличный способ быстро передать примеры запросов коллегам.
Документация должна содержать:
-
- Описание каждого эндпоинта и его параметров.
-
- Примеры успешных и ошибочных ответов.
-
- Описание лимитов (Rate Limits) и правил авторизации.
Заключение
Проектирование API — это поиск баланса между удобством для клиента и стоимостью поддержки для разработчика. Хорошее API — это то, которое интуитивно понятно. Если разработчик, открыв вашу документацию, может за 15 минут интегрировать ваш сервис без помощи поддержки — значит, вы всё сделали правильно.
Помните: API эволюционирует. Заложите гибкость в структуру с самого первого дня, не бойтесь версионирования и всегда думайте о том, как ваш интерфейс будет вести себя, когда количество записей в базе вырастет с тысячи до миллиона.

