Ошибка 1. Несогласованные формы ответов
Разные эндпоинты часто возвращают данные в разных структурах: один возвращает объект user, другой – сообщение об ошибке, третий – массив ошибок валидации. Такая разнородность заставляет клиентский код писать отдельные парсеры для каждого случая, что увеличивает количество багов и усложняет поддержку.
Решение. Ввести единый «конверт» для всех ответов. В успешных запросах помещать полезные данные в поле data, а в ошибочных – в поле error. Общий блок meta (например, requestId, timestamp) добавлять ко всем ответам. Пример:
// Успех
{
"data": { "id": 123, "name": "Jane", "email": "jane@example.com" },
"meta": { "requestId": "req_abc123" }
}
// Ошибка
{
"error": { "code": "USER_NOT_FOUND", "message": "User not found", "details": [] },
"meta": { "requestId": "req_def456" }
}
// Ошибки валидации
{
"error": {
"code": "VALIDATION_FAILED",
"message": "Request validation failed",
"details": [
{ "field": "email", "message": "Email is required" },
{ "field": "name", "message": "Must be at least 2 characters" }
]
},
"meta": { "requestId": "req_ghi789" }
}
Клиенту достаточно реализовать один универсальный парсер, который проверяет наличие error и обрабатывает data в остальных случаях.
Ошибка 2. Неправильное использование HTTP‑статусов
Часто API возвращают 200 OK даже при ошибках (например, «Unauthorized») или используют 500 Internal Server Error для ошибок валидации. Это нарушает семантику протокола и сбивает с толку разработчиков, использующих стандартные библиотеки HTTP.
Решение. Придерживаться базового набора кодов:
| Код | Сценарий |
|---|---|
| 200 | Обычный успех (GET, PUT, PATCH) |
| 201 | Создание ресурса (POST) |
| 204 | Успешное удаление (DELETE) без тела |
| 400 | Ошибочный запрос / неудачная валидация |
| 401 | Неавторизован |
| 403 | Доступ запрещён |
| 404 | Ресурс не найден |
| 409 | Конфликт (например, дублирование) |
| 500 | Внутренняя ошибка сервера |
Каждый ответ должен соответствовать своему коду, а тело ответа (см. Ошибка 1) уточняет детали.
Ошибка 3. Отсутствие версии API
Без явного указания версии клиент может «сломаться» после изменения контракта. Версионирование часто реализуется в URL (/v1/users) или в заголовке (Accept: application/vnd.myapi.v1+json).
Решение. Выбрать один способ и фиксировать его с первого релиза. При необходимости вводить новую версию, оставляя старую доступной до миграции клиентов.
Ошибка 4. Смешивание ресурсов и действий
Некоторые API используют глагольные пути (/createUser, /deleteUser) вместо чисто ресурсных (/users). Это усложняет кеширование, нарушает принципы REST и усложняет описание в OpenAPI.
Решение. Оставлять только ресурсы в пути и применять глаголы HTTP (POST – создать, DELETE – удалить, PATCH – частичное обновление). При необходимости добавить действие в виде подресурса (/users/{id}/activate).
Ошибка 5. Неоднозначные имена полей
Названия вроде msg, data, info часто дублируются в разных контекстах, что приводит к путанице.
Решение. Придерживаться консистентного стиля (camelCase, snake_case) и использовать осмысленные имена: userId, createdAt, errorMessage. При описании схем в OpenAPI явно указывать тип и обязательность полей.
Ошибка 6. Отсутствие пагинации в списках
Возврат полного списка записей (GET /orders) при большом объёме данных приводит к высоким задержкам и нагрузке.
Решение. Внедрить стандартную пагинацию (offset/limit или cursor‑based). В ответе включать метаданные page, pageSize, totalCount и ссылки next, prev в блоке meta.
{
"data": [ ... ],
"meta": {
"page": 2,
"pageSize": 50,
"totalCount": 1240,
"next": "/v1/orders?page=3&pageSize=50"
}
}
Ошибка 7. Неунифицированные форматы дат и чисел
Разные эндпоинты могут возвращать даты в ISO‑8601, UNIX‑timestamp или локальном формате, а числа – как строки. Это заставляет клиента выполнять дополнительные преобразования.
Решение. Выбрать один формат (рекомендовано ISO‑8601 для дат, числовой тип без кавычек) и фиксировать его во всех схемах. При необходимости документировать в OpenAPI.
Ошибка 8. Недостаточная документация ошибок
Клиенты часто получают лишь код 400 без описания, почему запрос отклонён. Это затрудняет отладку и автоматическое восстановление.
Решение. В каждом ответе error включать поле code (машинно‑читаемый) и message (человекочитаемый). При необходимости добавить массив details с информацией о конкретных полях. Сопоставьте коды с перечислением в спецификации.
Ошибка 9. Отсутствие ограничения скорости (rate limiting)
Без контроля количества запросов API подвержен злоупотреблениям, а клиентам сложно адаптироваться к перегрузкам.
Решение. Внедрить ограничение запросов (например, 100 запросов в минуту) и возвращать 429 Too Many Requests с заголовками Retry-After и X-RateLimit-Remaining. Клиентам следует обрабатывать такие ответы и реализовать экспоненциальный backoff.
Применяя перечисленные практики, разработчики получают предсказуемые, легко поддерживаемые и масштабируемые API. Последовательность в структуре ответов, корректное использование HTTP‑статусов и чёткая документация позволяют клиентским приложениям работать без излишних проверок и ошибок, а командам поддерживать сервисы с минимальными затратами.