Опирается на правила: R-FLD-1..7, R-RSP-1..8 и X-коды из REST API Style Guide → раздел JSON и формат ответов.

Важно знать

  • camelCase для полей JSON (orderId, createdAt, totalAmount).
  • Даты и время — ISO 8601 (2026-05-26T10:30:00Z или 2026-05-26).
  • Enum-значенияUPPER_SNAKE_CASE (IN_PROGRESS, CREDIT_CARD).
  • Коллекции — множественное число (items, errors, tags).
  • Идентификаторы — суффикс Id (orderId, customerId).
  • null в PATCH body — команда удалить поле (JSON Merge Patch).
  • null в response 2xx запрещён — отсутствующее поле = нет в JSON.
  • Envelope ({ success: true, data: ... }) — запрещён.
  • Коллекция{ "content": [...] } (не envelope, а структура пагинации).

JSON-контракт — лицо API. Каждое значение по умолчанию — что-то значит: null в response может означать «нет данных», «удалено», «не загружено», «error» — UCP убирает эту неопределённость. Нет null — нет поля.

Имена полей

R-FLD-1..5:

{
  "orderId": "550e8400-...",                       ✓ camelCase + Id-suffix
  "createdAt": "2026-05-26T10:30:00Z",             ✓ ISO 8601
  "totalAmount": 1500.00,                          ✓ camelCase
  "status": "IN_PROGRESS",                         ✓ UPPER_SNAKE_CASE enum
  "paymentMethod": "CREDIT_CARD",                  ✓
  "deliveryAddress": {                             ✓ camelCase
    "streetName": "Ленина",
    "zipCode": "123456"
  },
  "items": [...],                                  ✓ множественное число
  "tags": ["electronics", "sale"]                  ✓
}
  • Id-суффикс для идентификаторов: orderId, customerId, parentCategoryId.
  • ISO 8601 для дат: 2026-05-26 (date), 2026-05-26T10:30:00Z (date-time UTC).
  • UPPER_SNAKE_CASE для enum: IN_PROGRESS, OUT_OF_STOCK.

Boolean

R-FLD-7: префикс is/has/can опционально.

{
  "active": true,
  "hasDiscount": false,
  "canCancel": true
}

Главное — единообразие в проекте. Либо active/enabled, либо isActive/isEnabled — выбираем один стиль и применяем везде.

null в PATCH body — удалить поле

R-FLD-6: семантика запроса.

PATCH /api/v1/orders/{id}
Content-Type: application/merge-patch+json

{ "comment": null }

null в body — команда удалить поле comment. Это JSON Merge Patch (RFC 7396).

Не путать с null в ответе — это разная семантика.

Формат ответов

R-RSP-1..6:

Единичный ресурс — плоский объект

{
  "orderId": "550e8400-...",
  "status": "CONFIRMED",
  "totalAmount": 1500.00,
  "createdAt": "2026-05-26T10:30:00Z",
  "items": [
    { "itemId": "...", "productName": "Клавиатура", "quantity": 2, "price": 750.00 }
  ]
}

Без обёртки { data: ..., success: true }. Вложенные объекты и коллекции — допустимы внутри ресурса.

Коллекция — content + пагинация

{
  "content": [
    { "orderId": "..." }
  ],
  "page": 1,
  "size": 20,
  "totalElements": 243,
  "totalPages": 13
}

content — стандартное имя поля с данными. Это не envelope, это структура пагинированного ответаcontent всегда присутствует, плюс метаданные пагинации.

Создание — 201 + Location

HTTP/1.1 201 Created
Location: /api/v1/orders/550e8400-...

{
  "orderId": "550e8400-...",
  "status": "CREATED",
  "totalAmount": 0,
  "createdAt": "2026-05-26T10:30:00Z"
}

Обновление — 200 + ресурс

HTTP/1.1 200 OK

{
  "orderId": "550e8400-...",
  "status": "CONFIRMED",
  "totalAmount": 1500.00,
  "updatedAt": "2026-05-26T11:00:00Z"
}

Удаление — 204 No Content

HTTP/1.1 204 No Content

Пустое тело. Без { success: true } или подобных.

Action — 200 + обновлённый ресурс

POST /api/v1/orders/{id}/confirm

HTTP/1.1 200 OK

{
  "orderId": "550e8400-...",
  "status": "CONFIRMED",
  "confirmedAt": "2026-05-26T11:00:00Z"
}

Для async action202 Accepted (см. Batch, async, локализация).

null в успешном ответе — запрещён

R-RSP-X1: критическое правило.

{
  "orderId": "...",
  "status": "CREATED",
  "items": [],
  "comment": "Доставить до 18:00"
}

Если поле не заполнено — отсутствует в JSON, не "discount": null. Это:

  • Уменьшает размер ответа.
  • Упрощает клиентский код (if (data.discount) вместо if (data.discount && data.discount !== null)).
  • Защищает от ошибок типа "discount": null vs missing key.

В Spring настраивается:

@Bean
public ObjectMapper objectMapper() {
    return Jackson2ObjectMapperBuilder.json()
        .serializationInclusion(JsonInclude.Include.NON_NULL)
        .build();
}

R-RSP-X2: пустые строки "" вместо отсутствия — тоже запрещены. "" ≠ «нет данных», это есть, но пусто.

R-RSP-X3: nullable: true в OpenAPI — запрещено. Поле либо есть, либо отсутствует. В OpenAPI:

OrderResponse:
  type: object
  required:
    - orderId
    - status
    - items
  properties:
    orderId:
      type: string
      format: uuid
    discount:
      type: number
      description: 'Отсутствует если скидки нет'

Поле discount не в required — может отсутствовать. nullable: true не нужен.

Envelope запрещён

R-RSP-X4: критическое правило.

// ✗ — envelope
{
  "success": true,
  "data": { "orderId": "...", "status": "CREATED" },
  "error": null
}

// ✓ — плоский
{
  "orderId": "...",
  "status": "CREATED"
}

Почему envelope не нужен:

  • HTTP-статус уже сообщает success vs error (200 vs 4xx/5xx).
  • Ошибки — формат RFC 9457 (type, title, detail, status), см. Ошибки.
  • Коллекции оборачиваются в { "content": [...] } — это структура пагинации, не envelope.

Envelope добавляет noise без выгоды. Клиент пишет response.data.orderId вместо response.orderId — лишний уровень.

Пустые коллекции

R-RSP-7:

{ "items": [] }        ✓
{ "items": null }      ✗
{ }                    ✗ (если items required)

[] означает «коллекция есть, пуста». null или отсутствие — двусмысленно.

Что запрещено

АнтипаттернПравилоЧто взамен
null в response 2xxR-RSP-X1поле отсутствует
"" для отсутствияR-RSP-X2поле отсутствует
nullable: true в OpenAPIR-RSP-X3optional field
{ success: true, data: ... } envelopeR-RSP-X4плоский объект
customer_id snake_caseR-FLD-1customerId
created_atR-FLD-2createdAt (ISO 8601 string)
status: "in_progress"R-FLD-3"IN_PROGRESS"
id: "..." без суффиксаR-FLD-5orderId, customerId
{ items: null }R-RSP-7{ items: [] }
2026-05-26 10:30:00 без TR-FLD-22026-05-26T10:30:00Z
Content-Type: text/jsonR-RSP-1application/json

Куда дальше

  • REST API → JSON (нормативно) — формулировки.
  • URL и ресурсы — HTTP-методы и codes.
  • Query-параметры и пагинация — структура content для коллекций.
  • Ошибки RFC 9457 — формат error response.
  • Заголовки и трассировка — Location, ETag.
  • Версионирование — добавление optional поля non-breaking.