alltools.one
API
2025-06-05
7 min
alltools.one Team
APIRESTJSONResponse FormatBest Practices

Форматы ответов API: лучшие практики для согласованных API

Несогласованные ответы API — одна из главных жалоб фронтенд-разработчиков. Когда каждый эндпоинт возвращает данные в разной структуре, клиентский код обрастает множеством частных случаев. Единый формат ответа улучшает опыт разработчика, сокращает количество ошибок и делает ваш API самодокументируемым.

Обёртка ответа

Оборачивайте каждый ответ в единообразную структуру:

Успешный ответ (единичный ресурс)

{
  "data": {
    "id": "user_123",
    "name": "Alice",
    "email": "alice@example.com",
    "createdAt": "2024-01-15T10:30:00Z"
  },
  "meta": {
    "requestId": "req_abc123"
  }
}

Успешный ответ (коллекция)

{
  "data": [
    { "id": "user_123", "name": "Alice" },
    { "id": "user_456", "name": "Bob" }
  ],
  "meta": {
    "total": 142,
    "page": 1,
    "perPage": 20,
    "requestId": "req_def456"
  }
}

Ошибка

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Request validation failed",
    "details": [
      { "field": "email", "message": "Invalid email format" }
    ]
  },
  "meta": {
    "requestId": "req_ghi789"
  }
}

Ключевой принцип: клиент всегда проверяет наличие data или error на верхнем уровне. Никогда не смешивайте данные об успешном выполнении и информацию об ошибке в одном ответе.

Проверьте формат вашего ответа с помощью нашего JSON Валидатора.

Коды состояния HTTP

Используйте коды состояния правильно — это первое, что проверяет клиент:

Коды успеха

КодКогда использовать
200 OKУспешный GET, PUT/PATCH
201 CreatedPOST, создавший ресурс
204 No ContentУспешный DELETE (без тела ответа)

Коды ошибок клиента

КодКогда использовать
400 Bad RequestНекорректный синтаксис запроса
401 UnauthorizedОтсутствует или недействительна аутентификация
403 ForbiddenАутентифицирован, но не авторизован
404 Not FoundРесурс не существует
409 ConflictКонфликт состояния ресурса (дубликат)
422 UnprocessableСинтаксис корректен, но семантические ошибки
429 Too Many RequestsПревышен лимит запросов

Коды ошибок сервера

КодКогда использовать
500 Internal Server ErrorНеожиданный сбой сервера
502 Bad GatewayСбой вышестоящего сервиса
503 Service UnavailableВременная перегрузка или обслуживание

Проектирование ответов об ошибках

Хорошие ответы об ошибках помогают разработчикам быстро находить причину проблемы:

{
  "error": {
    "code": "RESOURCE_NOT_FOUND",
    "message": "User with ID 'user_999' not found",
    "details": [],
    "documentationUrl": "https://api.example.com/docs/errors#RESOURCE_NOT_FOUND"
  },
  "meta": {
    "requestId": "req_xyz789",
    "timestamp": "2024-01-15T10:30:00Z"
  }
}

Правила:

  • code — машиночитаемый код (постоянная строка, не HTTP-статус)
  • message — человекочитаемое сообщение (может измениться без нарушения работы клиентов)
  • details — ошибки на уровне полей при провале валидации
  • requestId — позволяет службе поддержки отследить запрос в логах

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

На основе смещения

Простая реализация, поддерживает переход к произвольной странице:

{
  "data": ["..."],
  "meta": {
    "page": 2,
    "perPage": 20,
    "total": 142,
    "totalPages": 8
  },
  "links": {
    "first": "/api/users?page=1&per_page=20",
    "prev": "/api/users?page=1&per_page=20",
    "next": "/api/users?page=3&per_page=20",
    "last": "/api/users?page=8&per_page=20"
  }
}

На основе курсора

Лучше подходит для данных в реальном времени и больших наборов данных:

{
  "data": ["..."],
  "meta": {
    "hasNext": true,
    "hasPrev": true
  },
  "links": {
    "next": "/api/users?cursor=eyJpZCI6MTQzfQ&limit=20",
    "prev": "/api/users?cursor=eyJpZCI6MTIzfQ&limit=20&direction=prev"
  }
}

Дата и время

Всегда используйте ISO 8601 с указанием часового пояса:

{
  "createdAt": "2024-01-15T10:30:00Z",
  "updatedAt": "2024-01-15T14:22:33+00:00",
  "expiresAt": "2024-12-31T23:59:59Z"
}

Чего следует избегать:

  • Unix-временные метки (неоднозначно: секунды или миллисекунды?)
  • Локальные даты без часового пояса
  • Нестандартные форматы вроде MM/DD/YYYY

Подробнее о работе с временными метками читайте в нашем руководстве по Unix Timestamps.

Null против отсутствующих полей

Два распространённых подхода:

Включать со значением null (явный):

{ "name": "Alice", "avatar": null, "bio": null }

Опускать отсутствующие поля (разреженный):

{ "name": "Alice" }

Рекомендация: Будьте последовательны в рамках вашего API. Явные значения null лучше для типизированных языков (клиенты знают, что поле существует). Разреженный формат лучше для сред с ограниченной пропускной способностью.

Версионирование ответов

Когда формат ответа меняется, используйте версионирование API:

GET /api/v2/users/123

Ломающие изменения, требующие версионирования:

  • Удаление поля
  • Изменение типа поля
  • Переименование поля
  • Изменение структуры обёртки ответа

Неломающие изменения (безопасны без версионирования):

  • Добавление новых полей
  • Добавление новых эндпоинтов
  • Добавление новых значений перечислений

FAQ

Стоит ли оборачивать успешные ответы в ключ data или возвращать ресурс напрямую?

Использование обёртки data обеспечивает единообразную структуру для всех ответов и оставляет место для метаданных, пагинации и ссылок рядом с данными. Прямой возврат ресурса проще для эндпоинтов с одним ресурсом. Большинство современных API используют подход с обёрткой ради согласованности.

Как обрабатывать частичные сбои в пакетных операциях?

Возвращайте 200 с ответом, который включает как успешные, так и неудачные результаты в объекте data. Использование 207 Multi-Status (WebDAV) — альтернативный вариант, но он реже применяется в REST API.

Связанные ресурсы

Published on 2025-06-05
API Response Formats: Best Practices for Consistent APIs | alltools.one