Что такое API и принципы чистого REST

API (Application Programming Interface) — это способ коммуникации между системами. Системами могут быть операционные системы, библиотеки или микросервисы. В контексте системного дизайна мы сосредотачиваемся именно на Web Server APIs.

Кажется, что REST API — это банально. Но если заглянуть в продакшен многих компаний, волосы встают дыбом от того, как спроектированы контракты. Давай разберем ключевые принципы.

1. Единая ответственность

Очень легко поддаться соблазну и начать запихивать кучу действий в один эндпоинт: изменить статус, отправить пуш-уведомление, пересчитать аналитику. Добавить это легко, но поддерживать или удалять — сущий ад. Если твой API начинает делать слишком много вещей одновременно — время его распилить.

 Плохой пример: POST /v1/social/handlePostEvent

JSON
{
  "userId": 101,
  "action": "createPost",
  "content": "Сегодня чудесная погода!",
  "mentionUsers": [102, 103],
  "notifyFollowers": true,
  "trackAnalytics": true
}

Правильный подход (Разделение ресурсов):

JSON
// 1. Создание поста: POST /v1/posts
{
  "userId": 101,
  "content": "Сегодня чудесная погода!",
  "visibility": "public"
}

// 2. Отдельный вызов для упоминаний: POST /v1/posts/{postId}/mentions
{
  "mentionedUserId": 102
}
2. Интуитивная консистентность

Разработчики (особенно мобильные клиенты) должны понимать, что делает API, даже не открывая документацию. Используй правильные существительные во множественном числе и стандартные Query-параметры:

  • GET /v1/users — получить список всех пользователей.
  • GET /v1/users?search=alex — фильтрация (поиск по имени).
  • GET /v1/users?limit=10&offset=20 — управление пагинацией.
3. Понятные и предсказуемые ошибки

Система обязана возвращать понятные ошибки. Проброс голой ошибки базы данных (Stack Trace) наружу — это не только плохой тон, но и угроза безопасности.

JSON
// Плохо: HTTP 500 (Проброс эксепшена)
{
  "error": {
    "code": "500",
    "message": "NullPointerException at com.example.UserController line 42"
  }
}

// Хорошо: HTTP 400 (Бизнес-ошибка)
{
  "error": {
    "code": "USER_NAME_REQUIRED",
    "message": "A user name is required to create a new account. Please include the 'username' field."
  }
}
4. Breaking changes — это зло

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

  1. Версионирование: Всегда закладывай версию в URL с самого старта проекта (/v1/users, /v2/users).
  2. Deprecation Policy: Если эндпоинт устарел, не удаляй его сразу. Добавь HTTP-заголовки Deprecation: true и Sunset (дата окончательного отключения), чтобы предупредить клиентов.
  3. Плавные изменения: Новые поля делай опциональными. Не меняй тип существующих полей.

Пример ответа с предупреждением о скором отключении API

JSON
HTTP/1.1 200 OK
Content-Type: application/json
Deprecation: true
Sunset: Sat, 31 Dec 2024 23:59:59 GMT
Link: ; rel="alternate"
Warning: 299 - "Deprecated API. This endpoint will be sunset on 2024-12-31."

{
  "orderId": 12345,
  "status": "completed"
}
5. Internal vs External API
  • Internal API: Скрыты глубоко в кластере. Используются для общения твоих микросервисов между собой (часто по gRPC вместо HTTP). Клиентам снаружи они недоступны.
  • External API: Смотрят «в мир» через API Gateway. Отдают данные мобильным приложениям, фронтенду или партнерам.

Часто сырые данные из микросервисов неудобно отдавать напрямую в мобильное приложение (придется делать 10 запросов). Для этого на стыке Internal и External сетей применяется паттерн BFF (Backend for Frontend) — специальный сервис, который собирает нужные данные внутри кластера и отдает их наружу одним красивым JSON-ответом. Подробнее мы разберем это на следующей неделе!