HTTP 200 — это ещё не «получилось»
Есть правило, которое кажется очевидным: код 200 — значит запрос удался. На нём построены половина обёрток над HTTP и почти все туториалы. И оно неверно чаще, чем хотелось бы.
Как это выглядит
Сервис отвечает 200 OK, заголовки в порядке, тело — валидный JSON. А внутри тела написано, что ничего не произошло:
Проверка response.ok на таком ответе возвращает true. Код едет дальше с пустыми руками и узнаёт об этом через три шага — там, где причину уже не видно.
Почему так делают
Причин обычно три, и ни одна не про лень:
- API вырос из формы на сайте: браузеру всегда отвечали страницей, а ошибку рисовали внутри неё.
- Между вами и сервисом стоит прокси или защита от ботов, которая переписывает коды на свои.
- «Не выполнено» для сервиса — штатный ответ, а не сбой: кончился баланс, не хватило прав, задача ещё считается.
Отдельно обидная разновидность — третья. Ответ «ещё не готово» приходит тем же кодом ошибки, что и «сломалось», и клиент бросает повторять именно тогда, когда повторить и надо было.
Что с этим делать
Не считать транспорт ответом. У HTTP свой слой: он говорит, доехал ли запрос. Успех операции живёт в теле, и разбирать его нужно отдельно — по полю, которое сервис назвал сам.


И ещё одно, из практики: заводя обёртку над чужим API, класс ошибки решайте по коду в теле, а не по тексту сообщения. Текст сервис перепишет на следующей неделе, и разбор строки сломается молча — ровно так же, как ломается вера в двухсотый код.
