Поширені помилки у контракті API, які порушують надійність фронтенду
Десять поширених помилок у контракті API, які псують надійність фронтенду: від зміни форматів відповідей та повідомлень 200 OK за кожну помилку до нестабільної сторінкування, разом із способами їх виправлення.
Джерела: 10 API Design Mistakes That Make Frontend Developers Hate You
API може бути ідеальним на папері, але все одно зробити життя всіх, хто розробляє на його основі, складним.
Ендпоїнт повертає коректний JSON. Код статусу відповідає очікуванням. Відповідь надходить швидко. З точки зору бекенду завдання здається виконаним. Проте інженери фронтенду бачать зовсім інше. Кожен виклик вимагає додаткової перевірки. Ендпоїнти, схожі за формою, повертають абсолютно різні дані. Повідомлення про помилки схожі на рядки журналу, а не на те, що має бачити користувач. Функція сторінкування поводиться непослідовно для різних ресурсів. Не існує надійного способу відрізнити порожнє значення від відсутнього чи відсутнє значення від невдалої заявки.
Уся ця розчарованість виникає не через те, що розробники фронтенду очікують, що бекенд буде адаптувати кожну відповідь під конкретний компонент. Добре спроєктований API не обов’язково має відображати певний інтерфейс користувача. Йому потрібна достатня чіткість, щоб багато різних інтерфейсів могли створювати прогнозовану поведінку щодо нього.
Міцні контракти API зменшують кількість припущень. Вони чітко визначають, що пройшло успішно, що зазнало невдачі, які поля є необов’язковими, як сортуються результати, чи існують додаткові сторінки, та які значення можна безпечно кешувати чи порівнювати з часом. Слабкі контракти переносять усю цю неоднозначність назовні, змушуючи кожен веб-сайт, мобільний додаток, панель керування та інтеграцію з третіми сторонами вигадувати власні тлумачення.
Саме тоді з’являється роздратування. Фронтенд перестає сприймати API як джерело істини та починає ставитися до нього як до чогось, що потрібно обходити.
1. Повернення різної форми відповіді з кожного ендпоїнта
Один ендпоїнт повертає простий масив. Інший розміщує свій вантаж всередині ключа data. Третій поєднує поля result, message та success. Маршрут з пагінацією зберігає свої записи під ключем items, тоді як сусідній маршрут використовує для цього ключ rows. Якщо ви видалите об’єкт через один контролер, ви отримаєте видалений запис; якщо через інший — зовсім нічого.
Якщо розглядати кожен ендпоїнт окремо, жодна з цих відповідей не є складною для розуміння. Проблеми виникають, коли команда фронтенду намагається створити спільну, повторно використовувану логіку для взаємодії з усім API разом.
Немає способу створити єдиний помічник запитів, механізм обробки помилок чи адаптер для сторінкування з упевненістю, оскільки кожен ендпоїнт потребує власного рішення. Компоненти змушені працювати з надзвичайно глибокими та неоднорідними структурами лише для отримання потрібної значення:
const users = response.data.result.users;
const orders = response.items;
const reports = response.data.rows;
Очевидною проблемою є дублювання коду для мапування. Ще більшою проблемою є непередбачуваність. Коли розробник фронтенду стикається з ендпоїнтом, яким раніше не працював, у нього немає способу здогадатися про його структуру на основі поведінки решти API.
Однорідність не означає, що кожна відповідь мусить мати ідентичні поля. Один ресурс, список ресурсів, результат сторінкування, результат виконання команди та асинхронне завдання — усе це означає різні речі, тож цілком логічно, що їхня структура буде відрізнятися. Важливо те, щоб кожна з цих категорій мала структуру, яку фронтенд може впізнати з першого погляду.
Відповідь у вигляді списку завжди може містити свої записи разом із певними метаданими. Команда завжди може повернути або оновлений ресурс, або чітко визначений об’єкт результату. Помилки завжди можуть мати однакову документовану структуру. Стани порожнечі можна представити однаково у схожих кінцевих точках.
Єдинообразний дизайн відповідей дозволяє зберегти простоту інфраструктури фронтенду. Неоднорідний дизайн перетворює кожен екран на індивідуальний адаптер, налаштований під того розробника бекенду, хто створив конкретний маршрут.
2. Використання 200 OK для кожного результату
Деякі API відповідають кодом 200 OK незалежно від того, що насправді сталось, приховуючи справжній результат у тілі відповіді:
{
"success": false,
"message": "User not found"
}
Ця схема зазвичай починається як спрощення для обробки на стороні клієнта: кожен запит вирішується однаково, а фронтенд просто перевіряє прапорець success у тілі запиту.
На практиці це позбавляє значення того, що вже безкоштовно надавався рівень транспортування.
HTTP-клієнти, інструменти моніторингу, кеші, проксі, API браузерів та бібліотеки для отримання даних всі будуються навколо категорій кодів статусу. Відхилений запит може природним чином потрапити у стан помилки. Успішна операція створення може відрізнятися від звичайного читання даних. Конфлікт може оброблятися по-іншому, ніж недійсний вхідні дані чи відсутній токен автентифікації.
Коли кожна відповідь повертається як 200, фронтенд мусить пам’ятати про необхідність перевірки тіла запиту після кожного виклику. Якщо це забути, невдала операція може виглядати як успішна. Загальна логіка повторних спроб стає ризикованою, оскільки клієнт більше не може відрізнити тимчасову проблему сервера від помилки перевірки. Також погіршується можливість спостереження, адже панелі керування відображають хвилю успішних запитів, тоді як користувачі насправді стикаються з невдачами.
Протилежною помилкою є об’єднання всіх невдач у 500. Відсутній запис, некоректний запит, проблеми з правами, дубльовані значення та перебої у підсистемах — це не однакові види невдач. Об’єднання їх у одну загальну помилку сервера змушує фронтенд аналізувати текст повідомлення, щоб з’ясувати, що саме пішло не так.
Коди статусу ніколи не призначалися для того, щоб нести повне бізнес-значення відповіді, але вони мають точно класифікувати результат. Тоді тіло відповіді може містити будь-які структуровані деталі, які насправді потрібні інтерфейсу.
Фронтенд не повинен аналізувати фразу „Електронна пошта вже існує“, щоб з’ясувати, що відбувається конфлікт.
3. Надсилання тексту помилки без будь-якої структури
Просте повідомлення про помилку може бути достатнім для тих, хто читає журнали подій, але воно рідко надає інтерфейсу достатньо інформації для роботи.
Уявіть, що кінцева точка реєстрації відповідає щось на кшталт:
{
"message": "Validation failed"
}
З цього клієнт не має можливості дізнатися, яке поле спричинило проблему, яке правило було порушене, чи кілька полів відмовили одночасно, або навіть чи ця помилка взагалі пов’язана з формою.
У таких ситуаціях розробники змушені писати крихку логіку порівняння рядків: якщо у тексті згадується „електронна пошта“, потрібно додати помилку до поля введення пошти; якщо згадується „пароль“, потрібно показати попередження, пов’язане з паролем. Як тільки сервер змінює формулювання, виправляє опечатку, змінює регістр або додає локалізацію, ця логіка мовчки перестає працювати.
Кращий підхід — розділяти те, що має зрозуміти машина, від того, що має прочитати людина. Відповідь може включати стабільний код помилки, деталі за кожним полем та контекстуальну інформацію про запит, разом із повідомленням, яке можна безпечно відображати чи записувати.
З такою структурою фронтенд може вирішувати, як кожна помилка має виглядати на екрані. Помилки перевірки даних на рівні поля можна показувати поруч із відповідним полем введення. Помилка авторизації може призвести до перенаправлення або приховування недоступної операції. Помилка конфлікту може запропонувати користувачеві спосіб її вирішення. Тимчасова проблема з сервісом може зберегти те, що користувач вводив, та надати кнопку для повторної спроби замість того, щоб стерти його роботу.
Усе це не означає необхідності включати у відповідь сирі записи про виникнення винятків чи рядки помилок бази даних — це зазвичай розкриває внутрішню структуру реалізації та лише ускладнює роботу користувача. Завданням бекенду є перетворювати низькорівневі помилки на стабільні, чітко визначені помилки домену.
Добре спроєктований пакет даних про помилку дозволяє клієнту відповісти на три основні запитання: до якої категорії належить ця помилка, до якої частини інтерфейсу вона належить та чи є у користувача можливість щось з нею зробити.
Якщо пропустити таку структуру, кожен фронтенд-код, який її використовує, змушений буде самостійно створювати своє нестабільне тлумачення будь-якого тексту, який повертає бекенд.
4. Розглядання null, відсутніх полів, порожніх рядків та порожніх масивів як взаємозамінних
Усе, що є необов’язковим у API, потребує чіткого значення для опису його відсутності.
Поле, якого немає у вантажі даних, може означати, що його просто не запитували. Значення null може означати, що система чітко знає про відсутність даних. Порожня рядок може означати, що користувач вирішив не вводити текст, або це може бути лише наслідком того, що старіший код неправильно обробляє відсутні значення. Порожній масив може означати, що справді немає жодних пов’язаних елементів, або це може означати, що завантаження відношень зазнало невдачі, і його тихо замінили на порожній список.
Коли API поєднує ці формати без послідовності, фронтенд не має надійного способу дізнатися, з якою саме ситуацією він має справу.
Поле профілю може бути повністю пропущене в одній відповіді та з’явитися як null в іншій. Кінцева точка списку може повертати null замість порожнього масиву, коли немає чого показувати, що означає, що кожен компонент мусить перевіряти дані перед тим, як працювати з ними. Дата, яка недоступна, може відображатися як порожній рядок, що у свою чергу заважає бібліотекам обробки даних, які очікують коректного формату. Зв’язок, який не вдалося завантажити, може бути тихо відображений як порожній масив, через що справжня помилка виглядає точно так само, як законний стан порожнечі.
Природним наслідком є код фронтенду, наповнений заходами обережності для нормалізації даних, на кшталт:
const records = Array.isArray(response.records)
? response.records
: [];
const displayName =
response.displayName ?? response.name ?? "";
Певний рівень нормалізації є доцільним — зовнішні системи за своєю природою є непередбачуваними, і клієнти повинні протидіяти цьому. Проблема виникає тоді, коли фронтенд більше не враховує справжню зовнішню непередбачуваність, а натомість намагається виправити ситуацію за допомогою контракту API, який не може чітко визначити, що означає „нічого“.
Рішення полягає у тому, щоб API навмисно визначив, що означає кожен тип відсутності даних. Колекції повинні залишатися колекціями навіть тоді, коли в них немає даних, а не перетворюватися на null. Поля, які можуть законно бути порожніми, мають бути дозволеними до значення null навмисно, а не випадково. А коли поле зовсім пропускається, має існувати задокументована причина цього — наприклад, рідкісні набори полей, обмеження прав доступу чи специфічні проекції кінцевих точок.
Як тільки відсутність отримує чітке значення, стани інтерфейсу стають більш зрозумілими. Фронтенд може розрізняти ситуації «немає коментарів», «коментарі не були включені до цієї відповіді» та «коментарі не вдалося завантажити».
Це три абсолютно різні ситуації для користувача, хоча на перший погляд усі вони можуть здаватися ідентичними: порожня секція коментарів, де нічого не відображається.
5. Пряме використання необроблених моделей бази даних через API
Серіалізація об’єкта ORM безпосередньо та його надсилання у відповіді може здаватися найпростішим рішенням — об’єкт вже знаходиться у пам’яті, тож навіщо створювати ще один шар лише для його перетворення?
Проблема полягає у тому, що рядок бази даних та контракт API існують з різних причин.
Таблиця може містити внутрішні коди статусу, колонки з іноземними ключами, часові позначки м’якого видалення, метадані аудиту, шляхи зберігання чи залишкові колонки з попередньої міграції. Пряма серіалізація такої структури пов’язує кожного клієнта з виборами щодо зберігання даних, про які вони ніколи не мали знати.
Як тільки фронтенд починає покладатися на такі поля, як user_role_id, deleted_at, або на вкладену структуру взаємозв’язків, яка виникає через певну конфігурацію ORM, бекенд опиняється у скрутному становищі. Пізнє перейменування колонок, розділення таблиці, зміна поведінки активного завантаження даних чи міграція на інший сервіс — усе це, що мало б залишатися суто внутрішніми оптимізаціями, раптово стає причиною збоїв у публічному API.
Пряма серіалізація ентитетів також створює ризик випадкового розкриття інформації. Хтось додає новий стовпець у базу даних, і оскільки стандартний серіалізатор включає всі поля, вони з’являються у відповідях API без будь-якого рішення щодо цього. Внутрішні нотатки, конфіденційні метадані чи дані, пов’язані з безпекою, можуть витекти таким чином без будь-якого свідомого дизайнерського рішення.
Спеціалізована модель відповідей вирішує цю проблему, функціонуючи як бар’єр. Вона чітко визначає, на які поля клієнти можуть покладатися, перетворює представлення на рівні зберігання у зрозумілі концепції домену та запобігає випадковому просочуванню внутрішньої структури у публічний контракт.
Це не вимагає ручного створення величезної функції мапування для кожного окремого ендпоінта. Серіалайзери з введенням коду, інструменти на основі схем та універсальні засоби мапування можуть значно скоротити кількість повторень. Важливо те, що форма відповіді є свідомим вибором, а не побічним продуктом того, що повертає ORM.
Розробники фронтенду повинні мати можливість працювати з стабільними концепціями продукту, а не з тією формою, яку наразі має таблиця бази даних.
6. Створення пагінації, на яку неможливо покластися
Пагінація здається простою, поки базові дані не змінюються під час її перегляду.
Ендпоїнт приймає page та limit, застосовує зсув та повертає частину записів. Фронтенд відображає елементи керування сторінкою та прокручує список. Усе це функціонує гармонійно, поки не додаються нові рядки, не видаляються старі або порядок сортування не залишається постійним.
Ситуація погіршується, коли кінцева точка з самого початку не гарантує стабільного порядку даних. Тоді двигун бази даних може повертати рядки у будь-якій послідовності, яку обере його механізм планування запитів. Два ідентичні запити, надіслані один за одним, можуть повертати рядки у різному порядку, навіть якщо в даних не відбулося жодних суттєвих змін.
Це проблема, яку фронтенд не може вирішити самостійно. Все залежить від того, чи надасть бекенд детермінований порядок даних разом із метаданими сторінкування, які справді мають значення.
Пагінація на основі офсету у поєднанні з гарантованим порядком сортування добре працює для багатьох наборів даних. Однак для каналів, які часто змінюються, або для дуже великих колекцій пагінація на основі курсора зазвичай краще справляється з постійними змінами. Вибір підходу залежить від продукту, але яким би варіантом ви не скористалися, у контракті має бути чітко вказано, як клієнт переходить між елементами колекції.
У відповіді щодо пагінації клієнт також має отримати відповіді на деякі практичні запитання. Чи існує наступна сторінка? Яке значення курсора має використовуватися у наступному запиті? Чи є загальна кількість точною, це оцінка чи її навмисно не надають? Що має статися, якщо сторінка, яку наразі переглядає клієнт, стане порожньою через видалення елементів?
Коли кінцева точка повертає записи без надійного способу їх навігації, фронтенд змушений відображати елементи сторінкування, яким він не може повністю довіряти. Користувачі бачать дублікати та відсутні записи, а за проблеми, які насправді є проблемами контракту, звинувачують інтерфейс.
7. Надсилання дат без вказівки часової зони
Дата майже ніколи не є просто звичайним рядком.
Часовий позначник без вказання часової зони може означати місцевий час сервера, час зберігання в базі даних, власний місцевий час кінцевого користувача або значення, яке мало бути у форматі UTC, але втратило свій зсув під час форматування. Тоді фронтенд змушений відображати, порівнювати, сортувати та ініціювати дії на основі значення, справжнє значення якого визначено лише частково.
Візьмемо відповідь на кшталт "2026-08-04 09:00:00". Вона не вказує, до якої саме миті стосується. Сесія браузера в Пакистані та сесія в Канаді можуть по-різному інтерпретувати цей рядок, а зміни часових поясів лише поглиблюють невизначеність.
Як загальне правило, абсолютні часові позначки повинні містити чітко вказаний зсув або бути представлені у стандартному форматі UTC. Календарні значення, які не прив’язані до конкретної миті, такі як дата народження чи дата оплати, повинні залишатися простими датами та не підлягати тихому зсуву між часовими поясами.
Це розрізнення має реальні наслідки. Якщо перетворити дату народження, збережену як північ на нуль UTC, у місцевий час, деякі користувачі побачать неправильний день — той, що передує. Навпаки, якщо сплановану подію розглядати лише як рядок з датою, усі побачать, що вона відбувається за часом їхнього місцевого годинника, а не у один і той самий спільний момент.
API також повинен бути послідовним щодо точності та формату, які він використовує у всіх кінцевих точках. Проблемою є ситуація, коли одна кінцева точка повертає секунди за системою Unix, інша — мілісекунди, а третя — якийсь специфічний формат рядка.
Розробники фронтенду здатні форматувати дату відповідно до локалі користувача. Однак вони не можуть відновити часову зону, про яку API спочатку їм нічого не повідомляв.
Проблеми, пов’язані з часовими поясами, є особливо дратівливими, оскільки зазвичай команда бекенду, яка працює у своєму часовому поясі, функціонує без проблем, а проблеми виникають лише у користувачів, які знаходяться в іншому місці.
8. Примусове об’єднання даних на простих екранах за допомогою ланцюгів запитів
Сторінка отримує інформацію про поточного користувача. Як тільки користувач повертається, сторінка отримує інформацію про його організацію. Після отримання даних про організацію сторінка отримує інформацію про дозволи. Лише після цього сторінка отримує записи, які користувач дійсно має право бачити.
Хоча кожен окремий ендпоїнт відповідає швидко, загалом екран може знадобитися кілька секунд, перш ніж він покаже щось корисне.
Ця схема зазвичай виникає, коли API моделюється виключно навколо нормалізованих ресурсів серверного боку, без належної уваги до того, як клієнт насправді читає ці дані на практиці. Дизайн з боку сервера виглядає охайним та чистим, тоді як клієнту доводиться організовувати цілу послідовну процедуру для відображення лише одної сторінки.
Розробники фронтенду реагують на це, вкладаючи стани завантаження один у інший. Невдача на певному етапі може призвести до того, що екран залишиться напівініціалізованим. Керування скасуванням стає складним, якщо користувач відходить під час отримання даних. Крім того, однакова інформація часто запитується кілька разів, оскільки кожен з компонентів має окрему ланку в цьому ланцюжку.
Рішенням не є вивантаження всієї бази даних через один великий ендпоінт. Натомість бекенд має розпізнавати важливі шляхи дій клієнта та надавати моделі для читання, створені для їх ефективного обслуговування.
Наприклад, ендпоінт панелі керування може одночасно повернути підсумкові дані та флаги можливостей, необхідні панелі. Ендпоінт з деталями запису може об’єднати невеликі пов’язані об’єкти, які завжди потрібні для перегляду. У випадках, коли частини даних справді є незалежними одна від одної, паралельні запити також є розумним варіантом.
Запити у форматі графа, шари бекенд-фор-фронтенд, параметри розширення ресурсів та спеціально створені ендпоїнти — усе це є ефективними інструментами для цього. Конкретний архітектурний стиль має менше значення, ніж результат: загальнодоступні екрани не повинні змушувати браузер поступово працювати з графом взаємозв’язків бекенду, запит за запитом.
API не отримує кращих оцінок за дизайн лише тому, що кожен ендпоїнт чітко відповідає одній таблиці бази даних. Добре спроєктований контракт також має враховувати те, як дані насправді використовуються з іншого боку.
9. Приховування бізнес-правил за зеленим сигналом
Іноді ендпоїнт для виконання операцій повідомляє про успіх, навіть якщо основний результат ще не до кінця сформований.
Запит на звіт потрапляє у чергу для автоматичної генерації на фоні. Оплата переходить у статус «у процесі». Операція видалення запланована на виконання після певного періоду зберігання. Постачальник третьої сторони підтверджує отримання запиту, але не те, що виконав роботу.
Коли API відповідає тим самим пакетом даних про успіх, який використовується для справді завершених операцій, фронтенд ризикує повідомити користувачеві інформацію, яка ще не є правдивою.
Інтерфейс може повідомляти «Звіт готовий», хоча його все ще створюють. Він може видалити рядок зі списку, навіть якщо сервер лише позначив його для майбутнього видалення. Він може показувати оплату як завершену, хоча постачальник ще може відхилити її пізніше.
Клієнтам потрібен спосіб розрізняти операції, які вже виконані, прийняті, все ще у процесі, частково успішні або потребують подальших дій. Це не дрібниця реалізації — це безпосередньо визначає, що інтерфейс може чесно повідомити користувачеві.
Для операцій, які виконуються в реальному часі, часто доцільно моделювати їх як окремий об’єкт роботи або завдання з ідентифікатором та полем статусу. Стани, які знаходяться у певному проміжному стані, слід чітко вказувати окремо, а не об’єднувати під загальним поняттям „успіх“. Коли результат є частковим, у відповіді слід точно описати, що було виконано успішно, а що — ні.
Ця сама дисципліна корисна також під час повторних спроб. Якщо запит закінчився тайм-аутом, але сервер вже може ним займатися, фронтенд не повинен просто надсилати запит знову та сподіватися. Наявність ідентифікатора операції або ключа ідемпотентності дозволяє клієнту безпечно повторювати спроби чи перевіряти статус, не ризикуючи виникненням дублікатних побічних ефектів.
Відповідь про успіх має відображати лише ту гарантію, яку сервер може надати наразі — нічого більше.
Це справжнє джерело розчарування, коли інженерам фронтенду доводиться самостійно з’ясовувати, чи означає статус 200, що завдання виконане, лише розпочате, чи просто „жодна помилка не виникла під час виконання“.
10. Розвиток контракту без плану для старих клієнтів
Зміна API здається легкою, коли створюється єдиний фронтенд-гілка, яка розвивається паралельно з ним. Ви перейменовуєте поле, коригуєте код клієнта, випускаєте їх разом та переходите далі.
У реальних умовах все рідко відбувається таким чином.
Хтось може залишити стару вкладку браузера відкритою під час розгортання. Мобільний додаток може залишатися встановленим на пристрої протягом місяців без оновлень. Інтеграція з третьою стороною може почати використовувати ваші зміни лише за своїм графіком випуску. Старий кешований пакет JS може продовжувати надсилати запити до вашого нового бекенду, все ще очікуючи формату відповіді старого типу.
Видалення або зміна назви поля може тихо пошкодити код, який ніхто з команди бекенду не має можливості виправити миттєво.
Деякі з найбільш ризикованих змін на перший погляд не виглядають ризикованими. Заміна значення enum може тихо пошкодити логіку умовного форматування інтерфейсу. Зміна поля з непеременного на перемінний може порушити припущення, закладені у генеровані типи. Зміна стандартного порядку сортування може вивести пагінацію зі синхронності. Введення нового статусу помилки може спрямувати запит по зовсім іншому шляху обробки помилок на клієнті.
Керування цим починається з розуміння того, хто насправді використовує API. Внутрішні клієнти, які розгортаються синхронно з бекендом, зазвичай можуть толерувати швидші ітерації, ніж інтеграції, орієнтовані на публіку — але навіть суто внутрішні системи отримують користь від поступових змін та поетапного виходу з ужитку старих полів.
Практичні тактики включають: введення нових полів перед видаленням старих, відстеження реальних даних використання для визначення моменту, коли можна щось припинити підтримувати, проведення тестів контракту з ключовими користувачами та використання належної версіонування API, коли семантика змінюється настільки фундаментально, що неможливо плавно адаптуватися на місці.
Це зовсім не означає, що кожен історичний контракт має підтримуватися вічно. Суть у тому, щоб не дозволяти проблемам клієнта ставати „проблемою когось іншого з розгортанням“ лише через те, що бекенд був випущений раніше.
Як тільки інші системи починають залежати від API, його поведінка має життєвий цикл, який триває значно довше, ніж код, який його спочатку реалізував.
Дружелюбність до фронтенду не означає дозволити фронтенду диктувати умови API
Добре спроєктований API — це не той, який просто відтворює форму, яку певному компоненту React найзручніше використовувати. Це лише призведе до іншої, так само крихкої форми зв’язку.
Натомість він забезпечує стабільне значення домену, передбачувану структуру, чесну інформацію про результати та достатньо контексту, щоб клієнти могли створювати правильний досвід без необхідності здогадувань. Він чітко розрізняє відсутність даних від повної невдачі, роботу, яка все ще триває, від завершеної роботи, проблему з верифікацією від конфлікту, а також спосіб відображення чогось від способу його зберігання.
Команди фронтенду цілком здатні справлятися з справжньою складністю — пагінація, стани помилок, переходи під час завантаження, асинхронні процеси — усе це вони створюють щодня. Те, що насправді призводить до виснаження, — це випадкова складність, яка виникає через непослідовну структуру відповідей та відсутність семантичних сигналів, а не через саму проблему.
Найкращі взаємовідносини між бекендом та фронтендом ґрунтуються на спільному розробленні таких угод. Фронтенд визначає, які аспекти насправді впливають на поведінку користувача. Бекенд пояснює, які гарантії він може надати без ризиків та які операції природним чином виконуються протягом довшого часу. Результатом є API-угода, яка належить не повністю жодній зі сторін.
API викликає незадоволення з моменту, коли починає поширювати свою власну невизначеність назовні.
Кожен неоднозначний код статусу перетворюється на умовну гілку на клієнті. Кожна непослідовна структура відповіді — на ще одну функцію-адаптер. Кожен відсутній структурований код помилки — на крихке порівняння рядків. Кожне нестабільне поле — на ще одну захисну перевірку на значення null.
Усе це не означає, що добре створений API усуває всю роботу фронтенду.
Він лише забезпечує, щоб розробники фронтенду присвячували свій час реальній розробці продукту, а не постійному зворотному аналізу того, що мав сказати бекенд.