Backend

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

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

Когда разработчик впервые создает API, он обычно думает о том, как передать данные из базы в интерфейс. Но через год поддержки этого кода он осознает, что API — это не просто набор эндпоинтов, а контракт. И если этот контракт составлен плохо, любое изменение в бизнес-логике превращается в кошмар, который «ломает» всех клиентов: от фронтенда на React до мобильных приложений и сторонних интеграций.

В этой статье мы разберем, как проектировать API так, чтобы оно оставалось гибким, понятным и поддерживаемым на протяжении многих лет.

1. Выбор архитектурного стиля: Не всё есть REST

Первая ошибка новичка — слепое следование REST. Да, REST — это стандарт де-факто, но он не является универсальным решением. Прежде чем рисовать схему эндпоинтов, определитесь с задачами.

  1. REST (Representational State Transfer). Идеален для большинства CRUD-операций. Его сила в кешировании и стандартных HTTP-методах. Но когда данных становится много, вы сталкиваетесь с проблемой overfetching (получаете лишнее) или underfetching (делаете 10 запросов, чтобы собрать одну страницу).
  2. GraphQL. Спасение для сложных фронтендов. Позволяет клиенту самому определять структуру ответа. Однако он переносит нагрузку на сервер и усложняет кеширование.
  3. gRPC. Если вам нужно общение между микросервисами с минимальными задержками, забудьте про JSON и переходите на Protocol Buffers. Это бинарный протокол, который работает в разы быстрее.
  4. 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}

Правила «гигиены» именования:

  1. Существительные вместо глаголов. Ресурс — это объект. Действие определяется HTTP-методом.
  2. Множественное число. Используйте /users, а не /user. Это создает единообразие.
  3. Иерархия. Если ресурс принадлежит другому ресурсу, отразите это в пути: /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 Unauthorized vs 403 Forbidden — разница между «я не знаю, кто ты» и «я знаю, кто ты, но тебе сюда нельзя».
    • 429 Too Many Requests — когда клиент слишком усердно долбится в ваш API.

Важно: В теле ошибки всегда возвращайте машиночитаемый код ошибки (например, USER_NOT_FOUND) и человекопонятное описание.

4. Производительность и защита: Чтобы сервер не «лег»

Проектирование API — это не только про красивые ссылки, но и про выживание системы под нагрузкой.

Пагинация. Никогда не возвращайте список всех записей. GET /orders должен возвращать порцию данных.

    • Offset-based (limit и offset) — просто, но тормозит на больших объемах данных.
    • Cursor-based (after_id) — работает быстро и стабильно при постоянном добавлении новых записей.

Фильтрация, сортировка и поиск. Вместо создания пяти разных эндпоинтов, используйте параметры запроса: /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 (длинный срок жизни).
    • Валидация: Никогда не доверяйте входящим данным. Каждый параметр должен быть проверен на тип, длину и формат. Инъекции через API — классика жанра.
    • Принцип наименьших привилегий: Клиент должен иметь доступ только к тем полям, которые ему нужны. Не возвращайте весь объект User из базы (включая хеш пароля и внутренние флаги), создайте отдельный DTO (Data Transfer Object) для ответа.

6. Документация как часть продукта

API без документации не существует. Если разработчику нужно писать вам в личку, чтобы понять, какой параметр передавать — ваше API спроектировано плохо.

Инструментарий:

    • OpenAPI (Swagger). Стандарт индустрии. Позволяет не только описывать API, но и генерировать интерактивную песочницу, где можно потыкать запросы.
    • Postman Collections. Отличный способ быстро передать примеры запросов коллегам.

Документация должна содержать:

    • Описание каждого эндпоинта и его параметров.
    • Примеры успешных и ошибочных ответов.
    • Описание лимитов (Rate Limits) и правил авторизации.

Заключение

Проектирование API — это поиск баланса между удобством для клиента и стоимостью поддержки для разработчика. Хорошее API — это то, которое интуитивно понятно. Если разработчик, открыв вашу документацию, может за 15 минут интегрировать ваш сервис без помощи поддержки — значит, вы всё сделали правильно.

Помните: API эволюционирует. Заложите гибкость в структуру с самого первого дня, не бойтесь версионирования и всегда думайте о том, как ваш интерфейс будет вести себя, когда количество записей в базе вырастет с тысячи до миллиона.