📋
← Назад к руководствам

Использование JSON в REST API: лучшие практики

· Теги: json, rest-api, api-design, json-best-practices, pagination, web-development

JSON в REST API

JSON и REST API — идеальное сочетание. Лёгкий синтаксис JSON, встроенная поддержка массивов и универсальная языковая поддержка делают его форматом по умолчанию для современных веб-API. Но простого использования JSON в вашем API недостаточно — следование устоявшимся соглашениям и лучшим практикам гарантирует, что ваш API будет согласованным, интуитивно понятным и лёгким в интеграции.

Формат запросов и ответов

Единая структура конверта

Примите единый JSON-конверт для всех ответов API. Это делает обработку на стороне клиента предсказуемой и упрощает обработку ошибок.

{
  "status": "success",
  "data": {
    "user": {
      "id": 123,
      "name": "Alice",
      "email": "alice@example.com"
    }
  },
  "meta": {
    "requestId": "req-a1b2c3d4",
    "timestamp": "2026-07-19T10:30:00Z"
  }
}

Snake Case против Camel Case

Выберите одно соглашение об именовании и придерживайтесь его во всём API:

  • Camel Case (createdAt, firstName): распространён в экосистемах JavaScript/TypeScript
  • Snake Case (created_at, first_name): распространён в экосистемах Python, Ruby и PHP

Какой бы вариант вы ни выбрали, чётко задокументируйте его и рассмотрите использование слоя трансформации, если ваш бэкенд-язык использует другое соглашение.

HTTP-коды состояния с JSON

Правильные HTTP-коды состояния дополняют ваши JSON-ответы. Используйте их согласованно:

| Код состояния | Значение | Когда использовать | |-------------|---------|-------------| | 200 OK | Успех | Успех GET, PUT, PATCH | | 201 Created | Ресурс создан | Успех POST | | 204 No Content | Успешное удаление | Успех DELETE (без тела JSON) | | 400 Bad Request | Недопустимый синтаксис JSON | Некорректное тело запроса | | 401 Unauthorized | Требуется аутентификация | Отсутствующий или недействительный токен | | 403 Forbidden | Недостаточно прав | Действительная аутентификация, но нет доступа | | 404 Not Found | Ресурс не существует | Недействительный ID или путь | | 422 Unprocessable Entity | Ошибка валидации | Семантические ошибки в корректном JSON | | 429 Too Many Requests | Превышен лимит запросов | Клиент превышает лимиты | | 500 Internal Server Error | Сбой на стороне сервера | Непредвиденные ошибки |

Стандартный формат ответа об ошибке

{
  "status": "error",
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Тело запроса содержит недопустимые поля",
    "details": [
      {
        "field": "email",
        "message": "Должен быть действительным адресом email",
        "code": "INVALID_FORMAT"
      },
      {
        "field": "age",
        "message": "Должно быть положительным целым числом",
        "code": "OUT_OF_RANGE"
      }
    ]
  }
}

Вложенные ресурсы

Представление связей

REST API часто требуется представлять связанные ресурсы. Вот распространённые шаблоны:

Встроенный (жадная загрузка):

{
  "order": {
    "id": 5001,
    "total": 29.99,
    "customer": {
      "id": 123,
      "name": "Alice",
      "email": "alice@example.com"
    },
    "items": [
      {
        "productId": 42,
        "name": "Widget",
        "quantity": 2,
        "price": 14.99
      }
    ]
  }
}

Ссылочный (ленивая загрузка) — используйте ID и предоставляйте отдельные эндпоинты:

{
  "order": {
    "id": 5001,
    "total": 29.99,
    "customerId": 123,
    "itemIds": [101, 102]
  }
}

Практическое правило: встраивайте связанные данные, которые всегда нужны вместе. Ссылайтесь на данные, которые извлекаются условно или в другое время.

Шаблоны пагинации

При возврате списков ресурсов пагинация необходима. Используйте единый формат пагинации:

Пагинация на основе смещения

{
  "status": "success",
  "data": [
    { "id": 1, "name": "User 1" },
    { "id": 2, "name": "User 2" }
  ],
  "pagination": {
    "page": 1,
    "perPage": 20,
    "totalItems": 156,
    "totalPages": 8,
    "links": {
      "first": "/api/users?page=1&perPage=20",
      "prev": null,
      "next": "/api/users?page=2&perPage=20",
      "last": "/api/users?page=8&perPage=20"
    }
  }
}

Пагинация на основе курсора (рекомендуется для больших наборов данных)

{
  "status": "success",
  "data": [
    { "id": 100, "name": "User 100" },
    { "id": 101, "name": "User 101" }
  ],
  "pagination": {
    "nextCursor": "eyJpZCI6MTAxfQ==",
    "hasMore": true
  }
}

Пагинация на основе курсора более надёжна для данных в реальном времени, где новые записи могут смещать границы страниц.

JSON в запросах API

Тела запросов POST / PUT

Принимайте JSON с заголовком Content-Type: application/json:

{
  "title": "Новая запись в блоге",
  "content": "Это содержимое...",
  "tags": ["json", "rest-api"],
  "published": false
}

Частичные обновления с PATCH

Используйте PATCH для частичных обновлений. Принимайте только те поля, которые должны измениться:

// PATCH /api/users/123
{
  "email": "newemail@example.com"
}

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

Используйте параметры запроса для манипуляции данными, сохраняя тело JSON чистым:

GET /api/users?filter[role]=admin&sort=-createdAt&search=alice
{
  "status": "success",
  "data": [ /* отфильтрованные, отсортированные результаты */ ]
}

Ограничение частоты запросов

Включайте информацию о лимитах запросов в заголовки ответа и, опционально, в тело JSON:

{
  "status": "error",
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Слишком много запросов. Пожалуйста, повторите попытку позже."
  },
  "meta": {
    "rateLimit": {
      "limit": 100,
      "remaining": 0,
      "resetAt": "2026-07-19T11:00:00Z"
    }
  }
}

Чек-лист лучших практик JSON

  • [ ] Используйте согласованное именование ключей (camelCase или snake_case во всём)
  • [ ] Возвращайте соответствующие HTTP-коды состояния с каждым ответом
  • [ ] Включите единый формат ошибок с машиночитаемыми кодами ошибок
  • [ ] Пагинируйте эндпоинты списков со стандартизированным объектом пагинации
  • [ ] Используйте JSON Schema для документирования и проверки структур запросов/ответов
  • [ ] Устанавливайте Content-Type: application/json на всех JSON-эндпоинтах
  • [ ] Сжимайте JSON-ответы с помощью gzip или brotli в продакшене
  • [ ] Обеспечьте максимальные лимиты размера полезной нагрузки (например, 1 МБ по умолчанию)
  • [ ] Используйте HTTPS для шифрования данных JSON при передаче
  • [ ] Структурируйте детали ошибок так, чтобы помочь клиентам в отладке, не раскрывая внутренние детали

Проверка JSON вашего API

Пропускайте ответы вашего API через JSON валидатор, чтобы обнаружить ошибки форматирования до того, как они достигнут клиентов. Согласованные, корректные JSON-ответы делают ваш API надёжным и удобным для разработчиков. Используйте наш инструмент JSON Formatter & Validator, чтобы тестировать ваши полезные нагрузки во время разработки.