← назад к разделу

CRUD-операций (создать, прочитать, обновить, удалить) хватает не всегда. Иногда нужно сослаться на ресурс без конкретного ID — «мой профиль», «последний деплой». Иногда нужно выразить бизнес-команду — «подтвердить заказ», «отменить подписку». Для обоих случаев в REST есть устойчивые приёмы.

Alias-сегменты: shortcut вместо ID

Обычный REST-путь выглядит так: GET /users/42. Клиент знает ID пользователя и подставляет его. Но что если клиент не знает ID — он хочет «текущего пользователя», «последний деплой», «основную платёжную карту»?

Alias-сегмент — это зарезервированное слово в пути вместо ID. Сервер сам понимает из контекста, какой конкретно объект имеется в виду.

me — псевдоним для текущего пользователя

GET /users/42        ← admin смотрит на любого пользователя
GET /users/me        ← обычный пользователь смотрит на себя

me — сокращение, которое сервер разворачивает в ID из токена авторизации. Клиенту не нужно хранить свой userId отдельно.

Когда me нужен. Задайте себе вопрос: «Мог бы администратор использовать этот же эндпоинт с чужим ID?» Если да — me полезен. Обычный пользователь ставит me, администратор ставит конкретный ID.

GET /users/me           ✓ — администратор мог бы GET /users/42
GET /users/me/settings  ✓ — настройки профиля

Когда me не нужен. Если эндпоинт всегда работает только с данными вызывающего и нет никакого «посмотреть чужое», me добавляет шум без пользы:

GET /users/me/orders  ✗ — заказы и так берутся из токена, /orders достаточно
GET /orders           ✓ — текущий пользователь видит только свои заказы

Ещё одно ограничение: me — это псевдоним для конкретного пользователя в коллекции users. Путь /me без users/ в начале не имеет смысла и использоваться не должен.

GET /me         ✗ — непонятно, к какому ресурсу относится
GET /users/me   ✓

me используют GitHub API, Google API, Spotify API, Microsoft Graph — это устоявшийся подход. Альтернативы (self, current-user) встречаются реже.

Временные и порядковые alias

Для выборки «крайнего» объекта из коллекции вместо длинных параметров можно использовать слова-псевдонимы:

GET /deployments/latest     — последний деплой (вместо ?sort=createdAt&order=desc&limit=1)
GET /subscriptions/current  — текущая подписка
GET /invoices/next          — следующий счёт
GET /billing-periods/previous — предыдущий расчётный период

Это работает только для singleton-выборки — когда контекст однозначно определяет один объект. Если таких объектов может быть несколько, нужна обычная фильтрация с параметрами.

Логические alias

Похожий приём для объектов, выделенных по бизнес-признаку:

GET /payment-methods/default  — платёжный метод «по умолчанию»
GET /addresses/primary        — основной адрес
GET /plans/active             — активный тарифный план
GET /documents/draft          — черновик

Каждый из них — ровно один объект, не список с фильтром.

Action-эндпоинты: доменные команды

Есть операции, которые не вписываются в CRUD. «Подтвердить заказ» — это не создание и не обновление в обычном смысле. Это бизнес-команда, у которой есть имя, побочные эффекты и, возможно, входные данные.

Для таких случаев используют action-эндпоинт: ресурс плюс глагол действия.

POST /orders/{id}/confirm
POST /orders/{id}/cancel
POST /orders/{id}/ship
POST /orders/{id}/refund

Как выглядит action-эндпоинт

Путь: ресурс с ID, затем глагол в инфинитиве.

Глагол — именно инфинитив, не существительное и не причастие:

POST /orders/{id}/confirm      ✓
POST /orders/{id}/confirmation ✗ — существительное
POST /orders/{id}/confirmed    ✗ — причастие

Метод — всегда POST. Даже если операция технически идемпотентна (повторный вызов даёт тот же результат), используется POST. Причина простая: action — это команда, а не замена ресурса. PUT означает «положи вот это состояние», POST означает «выполни вот это действие». Семантика важнее.

Входные данные — в теле запроса:

POST /orders/{id}/ship
Content-Type: application/json

{
  "trackingNumber": "TR-123456",
  "carrier": "DHL"
}

Если параметров нет, тело может быть пустым.

Когда action, а когда PATCH

Частая дилемма: изменить статус заказа — это PATCH /orders/{id} с { "status": "CONFIRMED" } или POST /orders/{id}/confirm?

Ориентир простой: если у операции есть доменное имя и побочные эффекты (события, переходы состояний, уведомления) — это action. Если просто меняется значение поля без особой логики — PATCH.

PATCH /orders/{id} { "description": "..." }  ✓ — простое обновление поля
POST /orders/{id}/confirm                    ✓ — доменная команда, статус-машина
POST /orders/{id}/cancel                     ✓ — есть имя, есть побочные эффекты
PATCH /orders/{id} { "status": "CANCELLED" } ✗ — скрывает доменный смысл за полем

Action-эндпоинты делают API читаемым: в логах сразу видно POST /orders/42/confirm, а не абстрактное «order updated». Разграничение прав тоже проще — для каждого действия своё разрешение.

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

me там, где эндпоинт работает только с данными текущего пользователя. Если нет admin-сценария с чужим ID, me не добавляет смысла — он просто лишний сегмент.

/me без users/. me — псевдоним для конкретного пользователя внутри коллекции users, не самостоятельный путь.

Существительное или причастие в action. /orders/{id}/confirmation — это выглядит как ресурс, а не команда. Правильно: /orders/{id}/confirm.

PUT для action. PUT /orders/{id}/confirm — семантически противоречие. PUT заменяет ресурс, POST выполняет команду.

Длинное имя action. cancelTheOrderImmediately — лишние слова. Достаточно cancel.

Коротко

  • Alias-сегмент — зарезервированное слово вместо ID; сервер разворачивает его из контекста.
  • me — псевдоним для текущего пользователя; нужен только когда есть admin-сценарий с чужим ID. Путь /me без users/ не используется.
  • Временные alias (latest, current, next, previous) — для singleton-выборки крайнего объекта.
  • Логические alias (default, primary, active, draft) — для объекта, выделенного по бизнес-признаку.
  • Action-эндпоинт — для доменных команд, у которых есть имя и побочные эффекты: ресурс + глагол-инфинитив, метод POST всегда.
  • Выбор между action и PATCH: есть доменное имя и побочные эффекты → action; простое изменение поля → PATCH.

Что почитать дальше

  • URL и ресурсы в REST API — структура пути, именование ресурсов.
  • HTTP-методы — семантика GET, POST, PUT, PATCH, DELETE.
  • Версионирование REST API — как эволюционировать эндпоинты без поломки клиентов.