Вопрос 12 · Раздел 6

Как правильно именовать REST endpoints?

Именование эндпоинтов — это создание понятного и предсказуемого API.

Версии по языкам: English Russian Ukrainian

Junior Level

Именование эндпоинтов — это создание понятного и предсказуемого API.

Основные правила:

  1. Используйте существительные, а не глаголы:
    • GET /users/1
    • GET /getUser/1
  2. Используйте множественное число:
    • /users, /orders, /products
    • /user, /order, /product
  3. Используйте kebab-case:
    • /audit-logs, /user-profiles
    • /audit_logs, /userProfiles
  4. Используйте нижний регистр:
    • /users/active
    • /Users/Active

Примеры:

GET    /users              — получить всех пользователей
GET    /users/1            — получить пользователя с ID 1
POST   /users              — создать пользователя
GET    /users/1/orders     — получить заказы пользователя
GET    /users?role=admin   — отфильтровать пользователей по роли

Фильтрация и поиск:

  • /users?role=admin&status=active — параметры запроса
  • /users/role/admin — не делайте URI иерархичным там, где иерархии нет

Middle Level

Senior-правила именования:

  • Множественное число: /users представляет коллекцию, /users/1 — элемент коллекции
  • Kebab-case: Дефис — стандарт для URL (RFC 3986), лучше воспринимается поисковиками
  • Нижний регистр: URL чувствительны к регистру на некоторых серверах (Linux/Nginx)

Как быть с действиями (Actions)?

Если действие не укладывается в CRUD (например, “активировать пользователя”):

  1. Resource-oriented (лучший): PATCH /users/1 с телом {"status": "ACTIVE"}
  2. Sub-resource: POST /users/1/activation — создаём “сущность активации”
  3. Controller-style (допустимо): POST /users/1/activate — для сложных команд

Поиск и фильтрация

  • /users?role=admin — Query Params для фильтрации
  • /users/role/admin — URI не должен быть иерархичным без иерархии

“Search-only” эндпоинты

В системах вроде Elasticsearch используют префикс _: POST /users/_search. Это помогает избежать коллизий с ID ресурсов.

Пограничные случаи

  • Trailing Slash: /users/ и /users — два разных ресурса. Настройте StrictTrailingSlashPatternMatch. По умолчанию Spring Boot 3+ делает 308 redirect с /users/ на /users. Если это нежелательно, настройте useTrailingSlashMatch в конфигурации.
  • ID в пути vs в заголовке: Как правило, не передавайте ID текущего пользователя в пути, если он уже есть в JWT. Используйте /users/me/profile. Исключение — административные эндпоинты, где админ работает с чужим ID. Это предотвращает IDOR (Insecure Direct Object Reference) атаки.
    • IDOR (Insecure Direct Object Reference) — атака, при которой злоумышленник подменяет ID в URL (/users/123/users/124), получая доступ к чужим данным. Защита: сверять ID из URL с ID в JWT.

Диагностика

  • 404 vs 405: Если ресурс существует, но метод не подходит — вернуть 405 Method Not Allowed с заголовком Allow, а не 404
  • URI Length: Браузеры и прокси ограничивают длину URL (2048 или 8192 символа). При слишком многих фильтрах — переходите на POST /_search

Senior Level

Сложные сценарии именования

Matrix Parameters

Редко используемая возможность URL;param=value (например, /users;status=active/orders). Spring MVC поддерживает через @MatrixVariable. Полезны для передачи параметров в середину пути.

IDOR Prevention

Как правило, не передавайте ID текущего пользователя в пути, если он уже есть в JWT. Используйте /users/me/profile — это предотвращает Insecure Direct Object Reference атаки.

  • IDOR (Insecure Direct Object Reference) — атака, при которой злоумышленник подменяет ID в URL (/users/123/users/124), получая доступ к чужим данным. Защита: сверять ID из URL с ID в JWT.

Производительность и Инфраструктура

  • URI Length Limit: Браузеры и прокси ограничивают длину URL. При слишком большом количестве фильтров — переходите с GET на POST /_search
  • Matrix Parameters: Spring MVC поддерживает @MatrixVariable для передачи параметров в середину пути

API Discovery

Хорошо спроектированное API позволяет вызвать OPTIONS /users и получить список доступных методов и параметров. Это позволяет клиентам динамически обнаруживать возможности API.

Edge Cases

  • Если ресурс /users/1 существует, но вы вызвали POST вместо GET — сервер должен вернуть 405 Method Not Allowed с заголовком Allow: GET, PUT, DELETE. Возврат 404 — ошибка дизайна
  • При интеграции с внешними системами документируйте все возможные query-параметры

🎯 Шпаргалка для интервью

Обязательно знать:

  • URI — существительное во множественном числе: /users, /orders, /products
  • Kebab-case для URL: /audit-logs, /user-profiles (RFC 3986)
  • Фильтрация через query-параметры: /users?role=admin&status=active, не через иерархию URI
  • Actions не-CRUD: PATCH /users/1 с телом или POST /users/1/cancellation (resource-as-action)
  • Trailing Slash: /users/ и /users — разные ресурсы; Spring Boot 3 делает 308 redirect
  • IDOR Prevention: использовать /users/me/profile вместо /users/{id}/profile, если ID уже в JWT
  • 405 Method Not Allowed с заголовком Allow — правильный ответ, если метод не подходит (не 404)

Частые уточняющие вопросы:

  • Как обрабатывать действия вроде «активировать»? — PATCH с {"status": "ACTIVE"} или POST /users/1/activation
  • Что такое IDOR и как защититься? — Подмена ID в URL; защита: сверять ID из URL с ID в JWT
  • Когда использовать POST /_search вместо GET? — При слишком большом количестве фильтров (URL > 2048 символов)
  • Что такое Matrix Parameters? — Редко используемые URL;param=value, поддерживаются через @MatrixVariable в Spring

Красные флаги (НЕ говорить):

  • «Глаголы в URL — это нормально» — URI = существительное, действие = HTTP метод
  • «404 — правильный ответ для неподходящего метода» — нужен 405 Method Not Allowed с заголовком Allow
  • «Единственное число лучше множественного» — множественное число — стандарт индустрии
  • audit_logs или userProfiles в URL» — kebab-case (audit-logs) — стандарт для URL

Связанные темы:

  • [[Что такое RESTful API дизайн]]
  • [[Стоит ли использовать глаголы в URL]]
  • [[Какие основные HTTP методы используются в REST]]
  • [[В чём разница между 401 и 403]]
  • [[Как организовать версионирование REST API]]