REST API: OpenAPI-метаданные и антипаттерны

OpenAPI-метаданные: operationId, теги. Антипаттерны REST API.

REST API OpenAPI антипаттерны

REST API OpenAPI антипаттерны: 20. OpenAPI-метаданные

20.1. operationId

REST API OpenAPI антипаттерны — каждый эндпоинт должен иметь уникальный operationId в формате camelCase:

/api/v1/orders:
  get:
    operationId: getOrders
  post:
    operationId: createOrder

/api/v1/orders/{id}:
  get:
    operationId: getOrder
  put:
    operationId: updateOrder
  delete:
    operationId: deleteOrder

/api/v1/orders/{id}/confirm:
  post:
    operationId: confirmOrder

/api/v1/orders/search:
  post:
    operationId: searchOrders

Паттерн: действие + ресурс (getOrders, createOrder, confirmOrder).

20.2. Теги (tags)

Группировка эндпоинтов по ресурсу. Один тег на ресурс, имя -- множественное число с заглавной:

tags:
  - name: Orders
    description: 'Управление заказами'
  - name: Users
    description: 'Управление пользователями'

/api/v1/orders:
  get:
    tags: [Orders]
  post:
    tags: [Orders]

/api/v1/orders/{id}/confirm:
  post:
    tags: [Orders]

Action-эндпоинты относятся к тегу родительского ресурса (confirm -> Orders).

20.3. summary и description

  • summary -- короткая фраза (до 80 символов), отображается в списке эндпоинтов
  • description -- подробное описание (markdown), отображается при раскрытии эндпоинта
/api/v1/orders/{id}/confirm:
  post:
    summary: 'Подтвердить заказ'
    description: |
      Переводит заказ из статуса CREATED в CONFIRMED.
      Заказ должен содержать хотя бы одну позицию.
      После подтверждения изменение состава заказа невозможно.

summary обязателен для каждого эндпоинта. description -- по необходимости, если логика неочевидна.


21. Антипаттерны

  • Глагол в URL для CRUD -- POST /createOrder -> POST /api/v1/orders
  • CamelCase в пути -- /orderItems -> /order-items
  • snake_case в пути -- /order_items -> /order-items
  • ID в теле вместо пути -- PUT /orders {"id":"..."} -> PUT /orders/{id}
  • GET с побочным эффектом -- GET /orders/{id}/approve -> POST /orders/{id}/approve
  • Глубокая вложенность -- /users/{id}/orders/{id}/items/{id}/comments -> /comments?itemId={id}
  • Множественное/единственное число вперемешку -- /order/{id}/items -> /orders/{id}/items
  • Версия в query -- /orders?version=1 -> /api/v1/orders
  • Бизнес-логика в query -- /orders?action=cancel -> POST /orders/{id}/cancel
  • Раскрытие внутренней модели -- /db/tables/orders/rows -> /api/v1/orders
  • Envelope-обёртка -- { "success": true, "data": {...} } -> плоский объект ресурса (см. раздел 11.8)
  • nullable: true вместо optional -- не использовать nullable, поле либо есть, либо отсутствует (см. раздел 11.7)
  • Rate limiting без заголовков -- 429 без Retry-After и RateLimit-* (см. раздел 14)
  • Deprecation без Sunset -- deprecated: true в OpenAPI, но без заголовка Sunset и даты отключения (см. раздел 16)
  • application/json для ошибок -- использовать application/problem+json для RFC 9457 (см. раздел 13)