标准JSON API响应格式?


695

是否存在用于构造来自API的JSON响应的标准或最佳实践?显然,每个应用程序的数据都是不同的,因此您不必担心很多,而是“响应样板”。我的意思的例子:

成功的请求:

{
  "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中学习到了,并且不会再构建它了……
DenysSéguret2012年

18
@dystroy:愿意解释您的评论吗?
FtDRbwLXw6 2012年

5
我对这个问题真的很感兴趣,因为我最近不得不设计一个JSON API,发现自己想知道它们是否是定义响应格式的任何标准。实际上,您的外观看起来不错,如果找不到标准,则值得使用。可惜的是,所提供的答案并未真正解决问题。
亚历克斯(Alex)

13
@Alex不幸的是,这是因为无论您走到哪里,都没有标准。不仅在JSON本身内,而且在如何将其用于RESTful应用程序或任何其他形式方面。每个人的做法都不一样。您可以随意遵循最佳实践(HTTP响应,有意义的包结构,将数据结构化以供系统使用的眼球),但是作为主要分发者的每个人所做的至少一件事情与其他事情有所不同。 ..没有标准,也不会有标准,因此要建立坚实的基础,并使其适合您。
Norguard 2012年

5
@Norguard有标准(请参阅我的答案)。实际上,关于标准的好处是您有很多选择。-Andrew Tanenbaum
Adam Gent

Answers:


638

是的,已经出现了一些标准(尽管对标准的定义有一些自由):

  1. JSON API -JSON API还涵盖创建和更新资源,而不仅仅是响应。
  2. JSend-简单,可能正在做的事情。
  3. OData JSON协议 -非常复杂。
  4. HAL - OData的一样,但目标是成为HATEOAS等。

还有JSON API描述格式:


19
谢谢。特别是JSend正是我想要的。它与我正在执行的操作类似,但是具有一些我的方法没有的优点。为了公平起见,@@ Trendly也非常接近他自己的答案。
FtDRbwLXw6

8
对于错误响应,我也特别喜欢HTTP API RFC问题草案。
Pieter Ennes

1
也许您想将code.google.com/p/json-service添加到描述格式列表中?
emilesilvis 2014年

1
我认为“推荐的Rails标准”标签有点夸大其词-这只是一个程序员的解决方案。不确定是什么使它成为“推荐标准”(特别是如果您查看宝石的流行程度-看起来根本没有很多人在使用它)?我个人认为大多数Rails程序员不会推荐此解决方案,因为使用响应正文而不是HTTP标头表示状态
Iwo Dziechciarow 2014年


194

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
我不确定是否可以通过PlayJson这样的服务器端JSON API来处理此问题,无论哪种方式都没有关系。@Steely,您的链接已断开
Rhys Bradbury

3
需要提供失败列表(例如验证问题)的错误呢?
Xeoncross

1
@Xeoncross单击单词上的链接error,Google的页面提供了此示例
MI Wright

@Xeoncross您可以使用error.errors []返回失败列表,定义为:“包含有关该错误的任何其他信息的容器。如果该服务返回多个错误,则error数组中的每个元素代表一个不同的错误。” 顶级错误可能会提到“请求输入验证失败”,并且error []数组将为每个发生的特定验证失败提供一个条目。
詹姆斯日报

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 2014年

简单明了。在我看来,比jsend更好,因为jsend可以将错误与失败区分开。
Josue Alexander Ibarra 2014年

1
我使用这种模式,但也与被叫字段messages这是一个消息的阵列而不是单个字符串。
2015年

4
答案几乎是记录良好的JSend的副本,它很简单而且非常有用。它们fail为典型的验证问题提供了第三种状态,而error仅与致命错误(如db错误)一起使用。
s3m3n

成功的原因:如果200标题中包含标题,为什么还要添加一个status字段?只需直接返回数据对象即可。您知道,使用TypeScript之类的类型化FE语言可能会引起其他痛苦。
Deniss M.

84

假设您的问题与REST Web服务设计有关,更确切地说与成功/错误有关。

我认为有3种不同类型的设计。

  1. 使用HTTP状态代码来指示是否存在错误,并尝试将自己限制为标准错误(通常应该足够)。

    • 优点:这是独立于您的api的标准。
    • 缺点:关于实际发生情况的信息较少。
  2. 使用HTTP状态+ json正文(即使它是错误的)。为错误定义统一的结构(例如:代码,消息,原因,类型等),并将其用于错误,如果成功,则只需返回预期的json响应。

    • 优点:使用现有的HTTP状态代码并返回描述错误的json(仍提供有关发生的情况的更多信息)时,仍是标准的。
    • 缺点:输出json会因错误或成功而有所不同。
  3. 忘记http状态(例如:始终为200),始终使用json并在响应的根添加一个布尔responseValid和一个错误对象(代码,消息等),如果出现错误则将填充该错误对象,否则其他字段(成功)已填充。

    • 优点:客户端仅处理json字符串作为响应的主体,并且忽略status(?)。

    • 缺点:不太标准。

由您选择:)

根据API,我会选择2或3(对于JSON rest api,我更喜欢2)。我在设计REST Api时经历的另一件事是,每种资源(url)的文档重要性:参数,正文,响应,标头等以及示例。

我还建议您使用jersey(jax-rs实现)+ genson(java / json数据绑定库)。您只需要在类路径中放入genson + jersey,即可自动支持json。

编辑:

  • 解决方案2是最难实现的,但优点是您可以很好地处理异常,不仅可以处理业务错误,更重要的是尽力而为,但从长远来看,您还是可以赢的。

  • 解决方案3在服务器端和客户端上都易于实现,但效果不佳,因为您必须将要返回的对象封装在还包含responseValid +错误的响应对象中。


2
您说我应该“为错误定义统一的结构”和其他类似的建议,但这正是我要问的问题。我猜答案是“不,关于这种结构,没有标准或最佳实践”。
FtDRbwLXw6 2012年

7
记录:HTTP状态代码不是标头。
pepkin88 2015年

3
“响应将不是json,而是html。” 错误!html与错误处理无关。响应可以是您支持的任何内容类型。
oligofren 2015年

2
@アレックスHTTP状态代码是HTTP响应的标头的状态行中的3位代码。在该行之后是标题字段,俗称“标头”。
pepkin88 '17

1
@アレックスHTTP上的Wikipedia页面很好地回答了您的问题,您可以在此处检查:en.wikipedia.org/wiki/…(链接至“响应消息”部分)
pepkin88 '17


19

以下是Instagram使用的json格式

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

19

我不会自夸地说这是一个标准,所以我将使用“我更喜欢”的形式。

我喜欢简洁的响应(在请求/ articles列表时,我想要一个JSON数组的文章)。

在我的设计中,我使用HTTP进行状态报告,一个200仅返回有效负载。

400返回一条消息,说明请求有问题:

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

如果模型/控制器/ URI不存在,则返回404

如果我这一边的处理出现错误,我会返回501并显示一条消息:

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

从我所看到的来看,相当多的REST-ish框架倾向于遵循这些原则。

理由

JSON应该是有效载荷格式,而不是会话协议。冗长的会话式有效负载的整个思想来自XML / SOAP世界以及造成这些过大设计的各种误导选择。在我们意识到这一切令人头疼之后,REST / JSON的全部目的就是要亲吻它,并坚持使用HTTP。我认为JSend 都不存在任何远程标准,尤其是其中没有更冗长的标准。XHR将响应HTTP响应,如果您将jQuery用于AJAX(就像大多数人一样),则可以使用try/ catchdone()/ fail()回调来捕获错误。我看不到将状态报告封装在JSON中比这更有用。


2
“ JSON是有效载荷格式...”。不,JSON是数据序列化格式。您可以使用它来传输所需的任何内容,包括会话协议或简单的有效负载。但是,您的KISS注释已达到目标,并且独立于JSON。最好使JSON专注于它的内容(如您所描述的成功数据或失败原因数据),而不是用一些必须不断组成并随后被剥离的杂乱的混合污染它。然后,您可以一路将其JSON数据存储在Couchbase中,然后将其按原样返回给应用程序。
Dirk Bester

1
也许我应该将其表述为“应该是有效载荷格式”,但除此之外,我坚持我的评论。您可以将会话/错误数据作为HTML文档中body标记的属性,但这并不能使其成为正确或明智的方法。
Bojan Markovic

16

为了值得,我做了不同的事情。成功的调用仅包含JSON对象。我不需要更高级别的JSON对象,该对象包含指示true的成功字段和具有JSON对象的有效负载字段。我只返回带有200或200范围内的适当JSON对象的标头中的HTTP状态。

但是,如果发生错误(400系列中的某个错误),我将返回格式正确的JSON错误对象。例如,如果客户端使用电子邮件地址和电话号码发布用户,而其中之一格式错误(即我无法将其插入我的基础数据库中),我将返回以下内容:

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

这里重要的一点是,“ field”属性必须与无法验证的JSON字段完全匹配。这使客户可以准确地知道他们的请求出了什么问题。另外,“消息”在请求的区域中。如果“ emailAddress”和“ phoneNumber”均无效,则“ errors”数组将包含两个条目。409(冲突)JSON响应正文可能如下所示:

{
  "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,亚马逊和其他公司)没有达成一致,尽管以上答案中提供了许多链接,但有些人试图标准化响应格式。

由于API的需求可能会有所不同,因此很难让所有人都加入并同意某种格式。如果您有数百万的用户在使用API​​,为什么还要更改响应格式?

以下是我对受Google,Twitter,Amazon和互联网上一些帖子启发的响应格式的看法:

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

摇摇欲坠的文件:

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


1
支持无信封的rest-api-response格式
KeremBaydoğan16年

@adnan kamilli->>> StatusCode:304,ReasonPhrase:“未修改”,版本:1.1,内容:<null>,Headers:{} <<<<这是restApi的正确响应吗?
阿诺德·布朗

@ArnoldBrown对于哪个API端点-您正在返回此代码的操作?
adnan kamili

它是用于上传图像(表单数据)的api的响应返回-客户端编写的api。
阿诺德·布朗

7

JSON的要点是它是完全动态和灵活的。将其弯曲成您想要的任何方式,因为它只是一组序列化的JavaScript对象和数组,它们植根于单个节点。

根节点的类型取决于您,根节点的内容取决于您,是否随响应发送元数据取决于您,是否将mime-type设置为application/json或保留为text/plain您(只要您知道如何处理边缘情况)。

构建您喜欢的轻量级架构。
就个人而言,我发现,分析,跟踪和MP3 / OGG服务和图像画廊服务和短信和网络数据包的网络游戏和博客,帖文,博客,评论有着非常不同的要求在什么条件发送,接收的内容以及如何使用它们。

因此,在执行所有这些操作时,我最后要做的就是尝试使每个标准都符合基于XML2.0或类似标准的相同样板标准。

就是说,使用对有意义并且经过深思熟虑的模式有很多话要说。
只需阅读一些API响应,记下您喜欢的东西,批评您不喜欢的东西,写下那些批评并理解为什么它们会以错误的方式摩擦您,然后考虑如何将您学到的知识运用到您的需求中。


1
谢谢您的答复,不过,我也不担心有效载荷本身。尽管您的示例在有效负载中发送/接收的内容以及如何使用这些有效负载方面都有非常不同的要求,但它们都必须针对响应本身解决相同的问题。即,他们都需要确定请求是否成功。如果是,请继续进行处理。如果不是,那是哪里出了问题。这是我在问题中所指的所有 API响应所共有的样板。
FtDRbwLXw6 2012年

返回所有状态的状态200,并为自己定义一个特定的错误有效负载,或者返回与错误相对应的状态,有效负载主体中有(或没有)更多详细信息(如果支持)。就像我说的那样,架构取决于您-包括任何元数据/状态信息。根据您喜欢的建筑风格,按照您的喜好来做是100%的空白。
Norguard

2
我意识到这是我想做的空白。我的问题的目的是询问就结构而言是否存在任何新兴标准。我不是在问“ JSON是什么以及如何使用它”,而是,“我知道如何使用JSON返回/构造我想要的任何东西,但我想知道是否正在使用任何标准结构或变得受欢迎。” 如果我误问了我很抱歉。无论如何,感谢您的回复。
FtDRbwLXw6 2012年

6

JSON-RPC 2.0定义了标准的请求和响应格式,并且在使用REST API之后令人耳目一新。


JSON-RPC_2.0提供的唯一例外是错误代码?数字错误代码不能完全代表发生的问题。
AgilePro

@AgilePro同意,数字错误代码不是很好,我希望规范的作者允许该code字段为字符串。幸运的是,该规范允许我们将所需的任何信息填充到错误的data字段中。在我的JSON-RPC项目中,我通常使用单个数字代码来处理所有应用程序层错误(与标准协议错误之一相反)。然后,我将详细的错误信息(包括指示实际错误类型的字符串代码)放入data字段中。
dnault,

2

对于以后的内容,除了公认的答案(包括HAL,JSend和JSON API)之外,我还要添加一些其他值得研究的规范:

  • JSON-LD,这是W3C建议书,指定如何在JSON中构建可互操作的Web服务
  • REST的离子超媒体类型,它声称自己是“ REST的一种简单直观的基于JSON的超媒体类型”

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

除了常识之外,没有违法或违法的标准。如果我们像两个人一样抽象地谈论这个问题,那么标准就是他们可以在最短的时间内用最少的单词准确理解彼此的最佳方式。在我们的例子中,“最少的字”是为提高传输效率而优化带宽,而“准确地理解”则是解析器效率的结构。最终最终得到的数据越少,结构越常见;这样它就可以穿过一个针孔,并且可以通过一个通用示波器(至少在最初)进行解析。

几乎在每种情况下,我都会看到针对“成功”和“错误”场景的单独响应,这对我来说有点模棱两可。如果在这两种情况下的响应不同,那为什么我们真的需要在此处放置“成功”标志?难道没有“错误”就是“成功”吗?是否可以在“成功”为TRUE且设置为“错误”的情况下进行响应?还是说,“成功”为FALSE,而未设置“错误”?仅一个标志是不够的?我宁愿只使用'Error'标志,因为我相信'Error'比'Success'少。

另外,我们真的应该将“错误”标记为吗?如果我想回答多个验证错误怎么办?因此,我发现拥有一个“错误”节点并将每个错误作为该节点的子节点更为有效;空的(错误计数为零)“错误”节点表示“成功”。


-2

Web API的最佳响应,移动开发人员可以轻松理解。

这是为了“成功”响应

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

这是针对“错误”响应

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

2
最好标准化您的属性。它们都是“ Return ...”值。但是数据没有前缀。我想说的是,删除所有的“ Return”前缀。
z0mbi3

包括“ Return”也很多余。
Jack Marchetti
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.