Грешки, които учат: HTTP кодове и Problem Details

Езици и бекендСредно ниво

От · основател и главен изпълнителен директор на Hábil. Така обучаваме тези, които изграждат системи, които не могат да се провалят.

За кого е: за този, който вече е писал API на какъвто и да е език и поне веднъж е отговорил с 200 с тяло, което казва {"error": …}, използвал е 500 за всичко, което е тръгнало на зле, или не е знаел да обясни разликата между 401 и 403, между 409 и 412, между 400 и 422; и за този, който използва чужди API и иска да спре да гадае какво да прави, когато те се провалят. Курсът е със средно ниво: предполага се, че знаеш какво е HTTP заявка, какво е JSON и как да стартираш сървър. Не се предполага, че познаваш спецификациите: всеки код се обяснява, когато се появи, и се обяснява защо съществува, а не само кой номер да се използва.

Какво ще знаеш в края: да избираш правилния код с въпрос, на който може да се отговори, да създаваш отговори с грешка, които една машина умее да чете (форматът Problem Details от RFC 9457), да решаваш кое се повтаря и кое не, и да доказваш с curl, че твоето API прави каквото казва. И да ти остане преценката, за да четеш спецификациите сам.

Какво ти трябва, преди да започнеш: компютър с Linux Mint, да умееш да отвориш терминал и да прочетеш кратка програма на TypeScript. Програмите използват Node 24 без нито една зависимост, а инструментът на целия курс е curl. Урок 0 подготвя средата.

Накъде нататък: ако искаш да видиш същата грижа, приложена към цяло API, статиите на Hábil за API, готови за AI агенти, за сигурност на API и за REST или gRPC продължават оттам, където този курс свършва.

Проектът, който ще изградиш

revisor, програмата, която проверява състоянието на списък от услуги —име, състояние и време за отговор—, с две лица:

  • Като сървър, малко API за управление на списъка с услуги, които наблюдава: добавяне, преглед, промяна, премахване и заявка за проверка. Това е лицето, което произвежда грешки, и трябва да ги произвежда добре.
  • Като клиент, този, който пита услугите и решава, според това, което му отговарят, дали са налични, ограничени, в поддръжка или паднали, и дали си струва да опита отново. Това е лицето, което чете грешки.

Това е същата задача като в курсовете по Go, Rust и TypeScript на Hábil. Променя се въпросът: не „успяхме ли да проверим услугата?“, а „какво каза услугата и какво да правя с това?“. А за да предизвикваме всеки код по желание, урок 0 изгражда тестов сървър, който отговаря с кода, който му поискаш.

Деветте урока

Те са девет, а не десет, защото каталогът е ограничен (23 кода) и една-единствена спецификация урежда тялото на грешката. Успешните отговори и пренасочванията споделят урок 1, защото в едно API трудното при тях са едни и същи три решения.

Урок Какво изграждаш Какво научаваш
0 Контрактът, който пътува по HTTP тестовият сървър и твоят инструмент: curl -i статус ред, заглавки и тяло; петте семейства; кодът е водещ, а тялото обяснява; какво прави една машина с код, който не познава; официалните регистри
1 Успешни отговори и пренасочвания: 200, 201, 202, 204, 301, 308 и 304 маршрутите, които добавят, преглеждат и премахват услуги; наследеният маршрут връщане, създаване, приемане или невръщане на нищо; Location; 202 и неговият ресурс за проследяване; 301 срещу 308; ETag и If-None-Match. Каре за сигурност: SSRF; revisor отхвърля loopback, частни мрежи, link-local или метаданни и ULA, проверява това преди всяка връзка (след разрешаването на DNS), а лабораторията допуска само едно изключение за точен IP и порт; пълната защита срещу DNS rebinding идва в урок 8
2 Клиентът сгреши (I): 400, 401, 403, 404, 405 и 415 входната точка на API седем стъпки по ред: маршрут → метод → удостоверение → разрешение → съществуване → формат → четене; WWW-Authenticate и Allow; кога 404 крие нарочно; 413 на ограничението от 16 KiB за тялото (предпазна мрежа, извън 23-те). Каре за сигурност: 404, който крие нарочно, и изброяването на ресурси
3 Клиентът сгреши (II): 409, 410, 412, 422 и 428 промяната на една услуга, без да се презапишат промените на друг човек конфликт, бизнес правило и предусловие; загубената актуализация; ETag с If-Match; 410 срещу 404; 400 срещу 422; версии на API: оттеглянето, обявено преди 410, с Deprecation (RFC 9745) и Sunset (RFC 8594)
4 Капацитет и повреди на сървъра: 429, 500, 502, 503 и 504 ограничение на заявките, поддръжка и една бавна зависимост кой е виновен; Retry-After; 500, 502 и 504; какво никога не се казва в грешка на сървъра. Каре за сигурност: какво никога не се казва в грешка и 429 като защита
5 Problem Details (RFC 9457) централният обработчик на грешки application/problem+json; петте члена; стабилен type; разширения; няколко проблема; от RFC 7807 към 9457; при about:blank title е на английски, защото RFC 9457 (§4.2.1) изисква да е фразата на HTTP статуса, докато detail може да е на испански
6 Повторни опити и идемпотентност един POST, който може да се повтори, без да дублира безопасни и идемпотентни методи; експоненциално отлагане с jitter; Idempotency-Key и защо още не е стандарт
7 Кой чете грешката: клиентът на revisor и AI агентите класифицирането на отговорите на проверяваните услуги таблица за решение по код и по type; поправяне, повторно удостоверяване, изчакване, съгласуване или отказ; как един AI агент използва същите полета
8 Проверимият контракт описанието в OpenAPI и матрицата от 23 сценария документиране на всяка грешка в OpenAPI 3.1; каталогът от типове проблеми; пълната матрица с curl; версиите на API в OpenAPI

В края на всеки урок има упражнения с решенията им. А дневникът е твой: записвай в него какво ти струва усилия.

23-те кода на курса

Семейство Кодове Урок
Успех 200, 201, 202, 204 1
Пренасочване и кеш 301, 308, 304 1
Клиентът сгреши: заявката 400, 401, 403, 404, 405, 415 2
Клиентът сгреши: състоянието 409, 410, 412, 422, 428 3
Капацитет и повреди на сървъра 429, 500, 502, 503, 504 4

Други се появяват мимоходом, за да се каже с какво се отличават от предишните (302, 307, 406, 501). 413 също не е сред 23-те, но revisor го връща: това е предпазната мрежа на ограничението от 16 KiB за тялото, което урок 2 обяснява заедно с 415. За всеки код курсът те учи кога да, кога не (и кой стои на негово място) и минималния правилен отговор.

Три принципа, които минават през целия курс

Кодът е водещ, а тялото обяснява, и двете казват едно и също. Кодът на статуса е онова, което чете всяка машина по пътя —браузърът, кешът, балансьорът, мониторът—; тялото е за този, който има нужда от подробностите. Тяло, което противоречи на кода или го замества, чупи всички, които не го четат.

Една добре проектирана грешка казва какво да се прави. Да се поправи входът, да се удостовери, да се изчака, да се прочете отново състоянието или да се откаже: почти винаги този, който получава грешката, е програма, а програмата не гадае. Затова всеки урок завършва с въпроса „какво трябва да направи този, който получава това?“.

Онова, което излиза навън, се проектира. Грешката е публична повърхност. Онова, което не се казва —трасировки на стека (stack traces), заявки, пътища, имена на машини, ключове— има същото значение като онова, което се казва, и се преподава там, където се появява, а не в завършващ модул за сигурност.

Честно предупреждение: Idempotency-Key и заглавките RateLimit-* още не са стандарт; те циркулират като чернови на IETF. Курсът ги преподава като шаблон, който API документира, а не като изискване на HTTP, и го казва всеки път, когато се появят.

Как разбираш, че си приключил

Курсът не свършва, когато си прочел урок 8, а когато твоето API изпълнява тези пет неща. Това са същите, които проверката потвърждава при всяка промяна:

  1. Матрицата от 23 сценария се изпълнява с една-единствена команда, и всеки ред проверява код, задължителни заглавки, тип на съдържанието и тяло.
  2. Никой отговор с грешка не е 200 или HTML. Всички са application/problem+json със стабилен type.
  3. Никое тяло на 5xx не съдържа трасировки на стека, заявки, пътища или ключове.
  4. Повторен POST със същия ключ не дублира нищо. Ако същият ключ дойде с ДРУГО тяло, отговорът е 422; ако дойде, докато първоначалната заявка още се изпълнява, отговорът е 409. Това идва от черновата на IETF «The Idempotency-Key HTTP Header Field» (draft-ietf-httpapi-idempotency-key-header-07, изтекла на 18 април 2026), която НЕ е стандарт.
  5. revisor класифицира 23-те случая с таблица и не повтаря онова, което не бива да се повтаря.

Уроци

  1. Урок 0 — Контрактът, който пътува по HTTP
  2. Урок 1 — Успешни отговори и пренасочвания: 200, 201, 202, 204, 301, 308 и 304
  3. Урок 2 — Клиентът сгреши (I): 400, 401, 403, 404, 405 и 415
  4. Урок 3 — Клиентът сгреши (II): 409, 410, 412, 422 и 428
  5. Урок 4 — Капацитет и повреди на сървъра: 429, 500, 502, 503 и 504
  6. Урок 5 — Problem Details (RFC 9457)
  7. Урок 6 — Повторни опити и идемпотентност
  8. Урок 7 — Кой чете грешката: клиентът на revisor и AI агентите
  9. Урок 8 — Проверимият контракт