Стандартний формат відповідей API JSON?


697

Чи існують стандарти або найкращі практики для структуризації відповідей JSON з API? Очевидно, що дані кожної програми різні, так що мене багато чого не стосується, а, скоріше, "відповідна котушка", якщо ви хочете. Приклад того, що я маю на увазі:

Успішний запит:

{
  "success": true,
  "payload": {
    /* Application-specific data would go here. */
  }
}

Помилка запиту:

{
  "success": false,
  "payload": {
    /* Application-specific data would go here. */
  },
  "error": {
    "code": 123,
    "message": "An error occurred!"
  }
}

16
Люди, напевно, навчилися з SOAP і більше не будуватимуть його ...
Denys Séguret

18
@dystroy: Хочете пояснити свій коментар?
FtDRbwLXw6

5
Мене це справді зацікавило, оскільки мені довелося нещодавно розробити API JSON і мені стало цікаво, чи існують якісь стандарти, що визначають формат відповіді. Насправді ваше виглядає досить приємно, і його варто використовувати, якщо ви не знайдете стандарт. Прикро, що надані відповіді насправді не стосуються цього питання.
Олексій

13
@ Алекс, на жаль, це тому, що де б ти не поїхав, не існує стандарту. Не тільки в межах самого JSON, але й з точки зору того, як його використовувати для RESTful додатків чи ще чогось подібного. Всі роблять це по-різному. Ви можете сміливо дотримуватися кращих практик (HTTP-відповіді, осмислена структура пакунків, погляд на структурування ваших даних для споживання вашою системою), але кожен, хто є головним розповсюджувачем, робить принаймні одне, що відрізняється від інших. .. Немає стандарту, і його, швидше за все, не буде, тому будуйте щось міцне і будуйте його так, щоб вам підходило.
Норгуард

Відповіді:


641

Так, існує декілька стандартів (хоча деякі свободи щодо визначення стандарту), які з'явилися:

  1. JSON API - JSON охоплює також створення та оновлення ресурсів, а не лише відповіді.
  2. JSend - Просте і, мабуть, те, що ви вже робите.
  3. Протокол JSON OData - Дуже складний.
  4. HAL - Як OData, але прагнучи бути схожим на HATEOAS .

Існують також формати опису API JSON:

  • Збійник
    • Схема JSON (використовується підкачкою, але ви можете використовувати її окремо)
  • WADL в JSON
  • RAML
  • HAL, тому що HATEOAS в теорії самоописується.

19
Дякую. Зокрема, JSend саме те, що я шукав. Це схоже на те, що я робив, але має деякі переваги, які мій метод не зробив. Справедливості до @trungly, JSend також дуже близький до власної відповіді.
FtDRbwLXw6

8
Для відповідей на помилки мені також подобаються деталі проблеми для проекту HTC API RFC.
Пітер Еннес

1
Можливо, ви хочете додати code.google.com/p/json-service до списку формату опису?
emilesilvis

1
Я думаю, що мітка "Рекомендований стандарт для Rails" є дещо завищеною - це лише одне рішення програміста. Не впевнені, що робить його "рекомендованим стандартом" (особливо якщо ви подивитеся на популярність дорогоцінного каміння - не схоже, що багато людей це використовують взагалі)? Я особисто не думаю, що більшість програмістів Rails рекомендували б це рішення через тело відповіді, а не заголовки HTTP для статусу
Iwo Dziechciarow

2
Посібник зі стилів Google JSON також є хорошим посиланням
MRodrigues

195

Посібник Google JSON

Повернення відповіді успіху data

{
  "data": {
    "id": 1001,
    "name": "Wing"
  }
}

Помилка повернення відповіді error

{
  "error": {
    "code": 404,
    "message": "ID not found"
  }
}

і якщо ваш клієнт - JS, ви можете if ("error" in response) {}перевірити, чи є помилка.


13
Перш за все, керівництво Google JSON рекомендує використовувати подвійні лапки замість одинарних лапок.
rpozarickij

1
Я не впевнений, чи можете ви це впоратися з API сервера JSON на зразок PlayJson, так чи інакше це не має значення. @Steely ваші посилання порушені
Rhys Bradbury

3
А що з помилками, які потребують подання списку відмов (наприклад, проблеми з валідацією)?
Xeoncross

1
@Xeoncross натисніть посилання на слово error, сторінка Google наводить приклад цього
MI Wright

@Xeoncross Ви можете повернути список відмов за допомогою error.errors [], визначеного як: "Контейнер для будь-якої додаткової інформації щодо помилки. Якщо служба повертає кілька помилок, кожен елемент у масиві помилок представляє іншу помилку." Можливо, помилка верхнього рівня вказуватиме "Запити невдалу перевірку введення", а масив помилок [] матиме один запис для кожної конкретної помилки перевірки.
James Daily

130

Я думаю, стандарт дефакто насправді не з'явився (а може і ніколи). Але незалежно, ось моя думка:

Успішний запит:

{
  "status": "success",
  "data": {
    /* Application-specific data would go here. */
  },
  "message": null /* Or optional success message */
}

Помилка запиту:

{
  "status": "error",
  "data": null, /* or optional error payload */
  "message": "Error xyz has occurred"
}

Перевага: однакові елементи вищого рівня як у випадках успіху, так і помилок

Недолік: коду помилки немає, але якщо ви хочете, ви можете змінити стан на код (успіх чи невдача), або ви можете додати ще один елемент верхнього рівня з назвою "код".


3
так, це правильний спосіб, якщо ви використовуєте POJO для розбору json! коли ми використовуємо POJO, нам потрібен статичний, нединамічний формат json!
LOG_TAG

Просте і суттєве. На мою думку, краще, ніж jsend, оскільки jsend відрізняє помилку від відмови.
Джозеу Олександр Ібарра

1
Я також використовую цей шаблон, але з полем, messagesяке називається масивом повідомлень замість однієї рядка.
StockBreak

4
Відповідь майже копія добре задокументованого JSend, що є простим і дуже корисним. Вони надали третій статус failдля типових проблем з валідацією, тоді errorяк вони використовуються лише зі смертельними випадками, такими як db-помилки.
s3m3n

для успіху: якщо він має 200в заголовках, навіщо вам навіть statusполе? просто поверніть об'єкт даних прямо. Ви знаєте, що це може заподіяти додатковий біль при введених мовах FE, таких як TypeScript.
Деніс М.

84

Якщо припустити, що ви ставитеся до питання про дизайн веб-сервісів REST, а точніше про успіх / помилку.

Я думаю, що існує 3 різних типи дизайну.

  1. Використовуйте лише код статусу HTTP, щоб вказати, чи виникла помилка, і спробуйте обмежити себе стандартними (зазвичай це повинно вистачити).

    • Плюси: це стандарт, незалежний від вашої програми.
    • Мінуси: менше інформації про те, що насправді сталося.
  2. Використовуйте HTTP Status + тіло json (навіть якщо це помилка). Визначте єдину структуру помилок (наприклад: код, повідомлення, причина, тип тощо) та використовуйте її для помилок, якщо це успіх, тоді просто поверніть очікуваний відповідь json.

    • Плюси: Ти все ж стандартний, коли ти використовуєш існуючі коди статусу HTTP і повертаєш json, що описує помилку (ви надаєте додаткову інформацію про те, що сталося).
    • Мінуси: вихід json буде змінюватися залежно від помилки чи успіху.
  3. Забудьте про статус http (наприклад, завжди статус 200), завжди використовуйте json і додайте в корені відповіді булева відповідьValid та об'єкт помилки (код, повідомлення тощо), який буде заповнено, якщо це помилка, інакше інші поля (успіх) заселяються.

    • Плюси: клієнт має справу лише з тією частиною відповіді, яка є рядком json, і ігнорує статус (?).

    • Мінуси: Менш стандартний.

Вибирати саме вам :)

Залежно від API я вибрав би 2 або 3 (я віддаю перевагу 2 для json rest apis). Ще одна річ, яку я зазнав при розробці REST Api - важливість документації для кожного ресурсу (URL): параметри, тіло, відповідь, заголовки тощо + приклади.

Я також рекомендую вам використовувати трикотаж (реалізація jax -rs) + genson (бібліотека для зв’язку даних java / json). Потрібно лише скинути джерсі genson + на своєму класі та json автоматично підтримується.

Редагувати:

  • Рішення 2 - найскладніше у застосуванні, але перевага полягає в тому, що ви можете добре впоратися з винятками і не лише бізнес-помилками. Початкові зусилля важливіше, але ви виграєте в довгостроковій перспективі.

  • Рішення 3 - це просто реалізувати як на стороні сервера, так і на клієнті, але це не так приємно, оскільки вам доведеться інкапсулювати об'єкти, які ви хочете повернути, в об’єкт відповіді, що містить також errorValid + помилку.


2
Ви говорите, що я повинен "Визначити єдину структуру для помилок" та інші подібні пропозиції, але саме про це я і запитую. Я думаю, що відповідь виявляється такою, що "ні, немає стандартних або найкращих практик щодо цієї структури".
FtDRbwLXw6

7
Для запису: код статусу HTTP не є заголовком.
pepkin88

3
"відповідь буде не json, а html." неправильно! html не має нічого спільного з обробкою помилок. відповідь може бути будь-якого типу вмісту, який ви підтримуєте.
олігофрен

2
@ ア レ ッ ク ス HTTP-код стану - це 3-значний код у рядку стану заголовка відповіді HTTP. За цим рядком знаходяться поля заголовків, розмовно їх називають також заголовками.
pepkin88

1
@ ア レ ッ ク ス Сторінка Вікіпедії на HTTP прекрасно відповідає на ваші запитання, ви можете перевірити їх там: en.wikipedia.org/wiki/… (посилання на розділ Повідомлення відповідей)
pepkin88


19

Далі йде інстаграм формату json

{
    "meta": {
         "error_type": "OAuthException",
         "code": 400,
         "error_message": "..."
    }
    "data": {
         ...
    },
    "pagination": {
         "next_url": "...",
         "next_max_id": "13872296"
    }
}

19

Я не буду настільки зарозумілий, щоб стверджувати, що це стандарт, тому я буду використовувати форму "я вважаю за краще".

Я віддаю перевагу стислий відповідь (коли я запитую список / статей, я хочу масив статей JSON).

У моїх розробках я використовую HTTP для звіту про стан, 200 повертає лише корисну навантаження.

400 повертає повідомлення про те, що було неправильно із запитом:

{"message" : "Missing parameter: 'param'"}

Поверніть 404, якщо модель / контролер / URI не існує

Якщо під час обробки з моєї сторони сталася помилка, я повертаю 501 із повідомленням:

{"message" : "Could not connect to data store."}

З того, що я бачив, досить багато рамок REST-ish, як правило, є такими.

Обґрунтування :

JSON повинен бути форматом корисного навантаження , це не протокол сеансу. Вся ідея багаторазових корисних навантажень сеансу походить із світу XML / SOAP та різних помилкових виборів, які створили ці роздуті конструкції. Після того, як ми зрозуміли, що все це було великим головним болем, вся суть REST / JSON полягала в тому, щоб поцілувати його та дотримуватися HTTP. Я не думаю, що в JSend є щось віддалено стандартне, і особливо це не стосується більш докладної серед них. XHR реагує на HTTP-відповідь, якщо ви використовуєте jQuery для свого AJAX (як і більшість), ви можете використовувати try/ catchта done()/ fail()зворотні виклики для збору помилок. Я не бачу, наскільки інкапсуляція звітів про стан у JSON є кориснішою за це.


2
"JSON - це формат корисного навантаження ...". Ні, JSON - це формат серіалізації даних. Ви можете використовувати його для передачі всього, що завгодно, включаючи протоколи сеансу або просто прості корисні навантаження. Ваші коментарі KISS є цільовими, але не залежать від JSON. Краще тримати JSON зосередженим на тому, що це таке (дані про успіх або дані про невдачі, як ви описуєте), ніж забруднювати його мешанками обох, які постійно мають бути складені та згодом позбавлені. Тоді ви можете пройти весь шлях і зберегти свої дані JSON, як є в Couchbase, і повернути їх, як належить до програми.
Дірк Бестер

1
Можливо, я мав би сформулювати це як "передбачається, що це формат корисної навантаження", але крім цього, я стою біля свого коментаря. Ви можете розмістити дані сеансу / помилки як атрибути тегу body в HTML-документі, але це не робить правильним чи розумним способом це зробити.
Боян Маркович

16

Для чого варто, я роблю це інакше. Вдалий дзвінок просто має об'єкти JSON. Мені не потрібен об'єкт JSON вищого рівня, який містить поле успіху, що вказує на істинне, і поле корисного навантаження, що містить об'єкт JSON. Я просто повертаю відповідний об’єкт JSON з 200 або будь-яким, що підходить в діапазоні 200 для статусу HTTP у заголовку.

Однак якщо є помилка (щось в сім'ї 400), я повертаю добре сформований об’єкт помилки JSON. Наприклад, якщо клієнт розміщує користувача з адресою електронної пошти та номером телефону, і один із них неправильно (тобто я не можу вставити його в базу даних), я поверну щось подібне:

{
  "description" : "Validation Failed"
  "errors" : [ {
    "field" : "phoneNumber",
    "message" : "Invalid phone number."
  } ],
}

Важливі біти тут полягають у тому, що властивість "field" має точно відповідати полі JSON, яке не може бути перевірено. Це дозволяє клієнтам точно знати, що пішло не так у їх запиті. Крім того, "повідомлення" є в мові запиту. Якщо і "emailAddress", і "phoneNumber" були недійсними, тоді масив "помилок" міститиме записи для обох. Орган відповіді JSON 409 (конфлікт) може виглядати так:

{
  "description" : "Already Exists"
  "errors" : [ {
    "field" : "phoneNumber",
    "message" : "Phone number already exists for another user."
  } ],
}

За допомогою коду статусу HTTP та цього JSON клієнт має все необхідне, щоб реагувати на помилки детермінованим способом, і він не створює нового стандарту помилок, який намагається завершити заміну кодів HTTP-статусу. Зверніть увагу, вони трапляються лише для 400 помилок. За що завгодно в діапазоні 200 я можу просто повернути все, що підходить. Для мене це часто подібний до HAL об'єкт JSON, але це насправді не має значення.

Я подумав над додаванням - це чисельний код помилки або в записах масиву "помилки", або в корені самого об'єкта JSON. Але поки що нам це не було потрібно.


9

Їх немає згоди щодо решти форматів відповідей api великих гігантів програмного забезпечення - Google, Facebook, Twitter, Amazon та інших, хоча у відповідях вище було вказано багато посилань, де деякі люди намагалися стандартизувати формат відповідей.

Оскільки потреби API можуть відрізнятися, дуже важко отримати всіх на борту та погодитись на певний формат. Якщо у вас є мільйони користувачів, які використовують ваш API, чому б ви змінили формат відповідей?

Далі я сприймаю формат відповідей, натхненний Google, Twitter, Amazon та деякі повідомлення в Інтернеті:

https://github.com/adnan-kamili/rest-api-response-format

Файл перемикання:

https://github.com/adnan-kamili/swagger-sample-template


1
подати заявку на конверт без формату відпочинку-api-відповіді
Керем Байдоган

@adnan kamilli - >>> StatusCode: 304, ReasonPhrase: 'Не змінено', Версія: 1.1, Зміст: <null>, Заголовки: {} <<<< це правильна відповідь restApi?
Арнольд Браун

@ArnoldBrown Для якої кінцевої точки API - дії, ви повертаєте цей код?
adnan kamili

його повернення у відповідь на api, що використовується для завантаження зображення (даних форми) - написані клієнтом api.
Арнольд Браун

7

Сенс JSON в тому, що він абсолютно динамічний і гнучкий. Зігніть його на будь-який примха, який ви хочете, тому що це лише набір серіалізованих об’єктів і масивів JavaScript, вкорінених в одному вузлі.

Який тип rootnode залежить від вас, що він містить, залежить від вас, чи ви надсилаєте метадані разом з відповіддю, чи встановите тип mime application/jsonабо залишите його так, як text/plainвам ( до тих пір, поки ви знаєте, як обробляти крайові корпуси).

Побудуйте легку схему, яка вам подобається.
Особисто я виявив , що аналітика відстеження та mp3 / OGG сервіровки і зображення галереї сервіровки і текстових повідомлень і мережеві-пакети для онлайн - ігор, і блог-пости і блог-коментарі все мають дуже різні вимоги в плані того , що надсилається і що отримується, і як їх слід споживати.

Отже, останнє, що я хотів би зробити, виконуючи все це, - спробувати зробити так, щоб кожен відповідав тому ж стандарту котлового шаблону, який базується на XML2.0 або щось подібне.

Однак це може сказати багато для використання схем, які мають для вас сенс і добре продумані.
Просто прочитайте кілька відповідей API, відзначте, що вам подобається, критикуйте те, що вам не подобається, запишіть ці зауваження і зрозумійте, чому вони вас протирають неправильно, а потім подумайте, як застосувати те, що ви навчились, до того, що вам потрібно.


1
Дякую за відповідь, але знову ж таки, я не переживаю за самі корисні навантаження. Хоча всі ваші приклади мають дуже різні вимоги щодо того, що надсилається / отримується в межах корисних навантажень і як витрачаються ці корисні навантаження , всі вони повинні вирішувати ті самі проблеми, що стосуються самої реакції . А саме, всі вони повинні визначити, чи був запит успішним. Якщо це було, приступайте до обробки. Якщо це не так, що пішло не так. Саме ця котловарна панель є загальною для всіх відповідей API, на які я посилаюся у своєму запитанні.
FtDRbwLXw6

Або поверніть статус 200 для всього, і визначте собі конкретну корисну навантаження помилки, або поверніть статус, співмірний з помилкою, з та / або без додаткових деталей в тілі корисного навантаження (якщо підтримується). Як я вже говорив, схема залежить від вас - включаючи будь-яку інформацію про мета / статус. Це на 100% порожній шифер, який стосується того, що вам подобається, виходячи з обраного архітектурного стилю.
Норгуард

2
Я усвідомлюю, що це порожній шифер, як мені подобається. Мета мого питання - запитати, чи існували якісь нові стандарти, що стосуються структури. Я не запитував "що таке JSON і як я ним користуюся", а навпаки, "я знаю, як використовувати JSON для повернення / структури всього, що я хочу, але хотів би знати, чи використовуються якісь стандартні структури або стає популярним ». Вибачте, якщо я неправильно сформулював питання. Дякуємо за вашу відповідь.
FtDRbwLXw6

7

JSON-RPC 2.0 визначає стандартний формат запиту та відповіді та є подихом свіжого повітря після роботи з API REST.


Єдине, що пропонує JSON-RPC_2.0 за винятками - це код помилки? Числовий код помилки не може з будь-якою вірністю представляти виниклу проблему.
AgilePro

@AgilePro Погоджено, числовий код помилки не дуже приємний, і я хотів би, щоб автори специфікації дозволили codeполі бути рядком. На щастя, специфікація дозволяє нам вводити будь-яку інформацію, яку ми хочемо, у поле помилки data. У своїх проектах JSON-RPC я зазвичай використовую єдиний числовий код для всіх помилок на рівні програми (на відміну від однієї зі стандартних помилок протоколу). Потім я поміщую детальну інформацію про помилку (включаючи рядовий код із зазначенням реального типу помилки) у dataполе.
дно

2

Для тих, хто прийде пізніше, окрім прийнятої відповіді, що включає API HAL, JSend та JSON, я додам ще декілька технічних характеристик, на які варто звернути увагу:

  • JSON-LD , що є рекомендацією W3C і визначає, як створити сумісні веб-сервіси в JSON
  • Ion Hypermedia Type для REST, який заявляє про себе як "простий та інтуїтивний тип гіпермедіа на основі JSON для REST"

1

Основний запропонований фреймворк виглядає добре, але об'єкт помилки, як визначено, занадто обмежений. Часто не можна використовувати одне значення для вираження проблеми, а натомість потрібен ланцюжок проблем та причин .

Я трохи провів дослідження і виявив, що найпоширеніший формат для повернення помилки (винятку) - це структура такої форми:

{
   "success": false,
   "error": {
      "code": "400",
      "message": "main error message here",
      "target": "approx what the error came from",
      "details": [
         {
            "code": "23-098a",
            "message": "Disk drive has frozen up again.  It needs to be replaced",
            "target": "not sure what the target is"
         }
      ],
      "innererror": {
         "trace": [ ... ],
         "context": [ ... ]
      }
   }
}

Це формат, запропонований стандартом даних OASIS OASIS OData і, здається, є найбільш стандартним варіантом там, однак, схоже, високий рівень прийняття будь-якого стандарту на даний момент. Цей формат відповідає специфікації JSON-RPC.

Ви можете знайти повну бібліотеку з відкритим кодом, яка реалізує це за адресою: Mendocino JSON Utilities . Ця бібліотека підтримує об'єкти JSON, а також винятки.

Деталі обговорюються в моєму блозі на тему " Поводження з помилками" в JSON REST API


0

Не існує норм порушень закону чи законів, окрім здорового глузду. Якщо ми абстрагуємо це так, як розмовляють двоє людей, стандарт - це найкращий спосіб, коли вони можуть зрозуміти один одного мінімальними словами за мінімальний час. У нашому випадку "мінімальні слова" - це оптимізація пропускної здатності для ефективності транспорту, а "точно зрозуміти" - це структура для ефективності аналізу; що в кінцевому підсумку закінчується тим, що менше даних і спільною структурою; щоб він міг пройти крізь отвір для штифтів і проаналізуватися через загальну область (принаймні спочатку).

Майже в усіх запропонованих випадках я бачу окремі відповіді на сценарій "Успіх" та "Помилка", що для мене є певною мірою неоднозначністю. Якщо відповіді в цих двох випадках різні, то чому нам насправді потрібно поставити прапор «Успіх»? Чи не очевидно, що відсутність "Помилки" - це "Успіх"? Чи можливо отримати відповідь, коли "Успіх" є ПРАВИЛЬНИМ із набором "Помилка"? Або, до речі, "Успіх" - НЕМАЛЬНИЙ, без "Помилки"? Лише одного прапора недостатньо? Я хотів би мати прапор "Помилка" лише тому, що я вважаю, що "Помилка" буде менше, ніж "Помилка".

Крім того, чи слід насправді робити «Помилку» прапором? Що робити, якщо я хочу відповісти на кілька помилок перевірки? Отже, я вважаю, що ефективніше мати вузол "Помилка" з кожною помилкою в якості дочірнього до цього вузла; де порожній (рахується до нуля) вузол "Помилка" позначатиме "Успіх".


-2

Найкращий відгук для веб-apis, який легко зрозуміють розробники мобільних пристроїв.

Це для відповіді "Успіх"

{  
   "ReturnCode":"1",
   "ReturnMsg":"Successfull Transaction",
   "ReturnValue":"",
   "Data":{  
      "EmployeeName":"Admin",
      "EmployeeID":1
   }
}

Це для відповіді "Помилка"

{
    "ReturnCode": "4",
    "ReturnMsg": "Invalid Username and Password",
    "ReturnValue": "",
    "Data": {}
}

2
Було б краще стандартизувати свої властивості. Усі вони є значеннями "Повернення ...". Але дані не мають префікса. Я б сказав, скиньте всі префікси "Повернення".
z0mbi3

Включно з "Поверненням" теж непотрібно.
Джек Марчетті
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.