REST и проектирование API

REST и проектирование Web API: ресурсы, глаголы, предсказуемые URL.

Суть: REST — это стиль проектирования API, где данные представлены как ресурсы (пользователи, заказы), доступные по понятным URL, а действия над ними выражены HTTP-глаголами (GET, POST, PUT, DELETE). Хороший REST-API предсказуем: по URL и методу ясно, что произойдёт.

Web API — это бэкенд без HTML, отдающий данные (обычно JSON) для фронтенда, мобильных приложений или других сервисов. REST задаёт правила, как такой API проектировать, чтобы он был понятным и единообразным.

Ресурсы и глаголы

МетодURLДействие
GET/api/usersСписок пользователей
GET/api/users/42Один пользователь
POST/api/usersСоздать пользователя
PUT/api/users/42Обновить целиком
DELETE/api/users/42Удалить

Заметьте: URL — это существительные (ресурсы), действие задаёт глагол (HTTP-метод). Не делайте /api/getUser или /api/deleteUser?id=42 — это анти-REST.

Идемпотентность и безопасность

GET — безопасный (не меняет данные) и идемпотентный. PUT и DELETE — идемпотентные (повтор даёт тот же результат). POST — нет: два POST создадут два ресурса. Это влияет на ретраи и кэширование.

Как работает под капотом

Когда клиент шлёт POST /api/users с JSON-телом, ASP.NET Core десериализует тело в C#-объект (DTO), валидирует его, передаёт в ваш метод. Вы создаёте ресурс и возвращаете 201 с заголовком Location, указывающим на новый ресурс. Клиент по этому заголовку знает, где забрать созданную сущность. Так REST остаётся самоописательным: ответы содержат не только данные, но и навигацию.

Частые ошибки

  • Глаголы в URL. /api/createUser вместо POST /api/users — нарушает REST и путает.
  • Неправильный метод. Удаление через GET опасно: поисковые боты и префетч могут «удалить» данные.
  • Игнорировать идемпотентность. Делать POST идемпотентным «вручную» без понимания — источник дубликатов.

Best practices

  • Множественное число для коллекций: /users, /orders.
  • Вложенность для связей: /users/42/orders.
  • Версионируйте API (/api/v1/users), чтобы менять контракт без поломки клиентов.

Уровни зрелости REST и где остановиться

Существует модель зрелости Ричардсона: уровень 0 — один URL и POST на всё, уровень 1 — отдельные ресурсы, уровень 2 — корректное использование HTTP-глаголов и кодов, уровень 3 — гипермедиа (HATEOAS, ссылки на связанные действия прямо в ответах). На практике большинство качественных API живут на уровне 2: ресурсы-существительные, правильные глаголы и статус-коды. Уровень 3 встречается реже — он мощный, но усложняет и сервер, и клиентов, поэтому добавляют его осознанно.

Хороший REST-дизайн — это ещё и продуманные детали: пагинация коллекций (через ?page=2&size=20), фильтрация и сортировка (?status=active&sort=name), частичное обновление через PATCH вместо полного PUT. Эти соглашения делают API предсказуемым: разработчик клиента, увидев одну вашу ручку, угадывает поведение остальных.

Версионирование и устойчивость контракта

API живёт долго, а клиенты обновляются не сразу, поэтому ломать контракт нельзя. Решение — версионирование: /api/v1/users, /api/v2/users, либо версия в заголовке. Старые клиенты продолжают ходить в v1, новые — в v2. Внутри одной версии действует правило обратной совместимости: добавлять поля можно, удалять и переименовывать — нельзя. Это дисциплина, без которой публичный API быстро превращается в источник поломок у потребителей.

Наконец, REST-ответы должны быть самоописательными в разумных пределах: при создании ресурса возвращайте заголовок Location и тело созданной сущности, при ошибке — понятную структуру (ProblemDetails). Чем меньше клиенту приходится «додумывать» по недокументированным признакам, тем надёжнее интеграция. Предсказуемость — главная ценность REST, важнее формальной чистоты.

Итог: REST делает API предсказуемым через ресурсы-существительные и глаголы-методы. Дальше — как принимать и валидировать входные данные.

Проверьте себя
1. Какой URL соответствует принципам REST для создания пользователя?
AGET /api/createUser
BPOST /api/users
CPOST /api/users/create
DGET /api/users/new
2. Какое свойство у метода GET?
AМеняет данные
BБезопасный и идемпотентный: не меняет данные, повтор даёт тот же результат
CСоздаёт ресурс при каждом вызове
DНе кэшируется никогда