ChatGPT解决这个技术问题 Extra ChatGPT

JSON API 响应格式有什么标准吗?

是否存在用于构建来自 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!"
  }
}
人们可能已经从 SOAP 中学到了东西,并且不会再构建它......
@dystroy:愿意解释您的评论吗?
我对这个问题非常感兴趣,因为我最近必须设计一个 JSON API,并且发现自己想知道它们是否是定义响应格式的任何标准。您的实际上看起来相当不错,如果您没有找到标准,看起来值得使用。很遗憾,所提供的答案实际上并没有解决这个问题。
@Alex 不幸的是,那是因为无论你去哪里,都没有标准。不仅在 JSON 本身内,而且在如何将它用于 RESTful 应用程序或任何其他类型的应用程序方面。每个人的做法都不一样。您可以随意遵循最佳实践(HTTP 响应、有意义的包结构、着眼于构建数据以供系统使用),但作为主要分销商的每个人都至少在做一件与其他人不同的事情。 .. 没有标准,也不太可能有标准,所以建造坚固的东西,建造适合你的东西。

x
xzilla

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

JSON API - JSON API 还包括创建和更新资源,而不仅仅是响应。 JSend - 很简单,可能你已经在做。 OData JSON 协议 - 非常复杂。 HAL - 像 OData,但目标是像 HATEOAS。

还有 JSON API 描述格式:

Swagger JSON Schema(由 swagger 使用,但您可以单独使用它)

JSON Schema(由 swagger 使用,但您可以单独使用它)

JSON 格式的 WADL

随机存取存储器

HAL,因为理论上 HATEOAS 是自我描述的。


谢谢你。特别是 JSend 正是我想要的。这与我所做的类似,但有一些我的方法没有的好处。公平地说,@trungly,JSend 也非常接近他自己的答案。
对于错误响应,我也特别喜欢 Problem Details for HTTP APIs RFC 草案。
也许您想将 code.google.com/p/json-service 添加到描述格式列表中?
我认为“Rails 的推荐标准”标签有点夸大其词——这只是一个程序员的解决方案。不确定是什么使它成为“推荐标准”(特别是如果您查看宝石的受欢迎程度 - 看起来根本没有很多人在使用它)?我个人认为大多数 Rails 程序员不会推荐这种解决方案,因为使用响应正文而不是 HTTP 标头作为状态
Google JSON Style Guide 也是一个很好的参考
g
ggorlen

谷歌 JSON 指南

成功响应返回 data

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

错误响应返回 error

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

如果你的客户端是JS,你可以使用if ("error" in response) {}来检查是否有错误。


我不确定您是否可以从像 PlayJson 这样的服务器端 JSON API 处理这个问题,无论哪种方式都没有关系。 @Steely 你的链接坏了
需要提供失败列表的错误(如验证问题)呢?
@Xeoncross 点击单词 error 上的链接,谷歌的页面给出了一个例子
@Xeoncross您可以使用error.errors []返回失败列表,定义为:“有关错误的任何其他信息的容器。如果服务返回多个错误,则错误数组中的每个元素表示不同的错误。”也许顶级错误会提到“请求输入验证失败”,errors[] 数组对于发生的每个特定验证失败都会有一个条目。
@Steely Wing ->>> StatusCode: 304, ReasonPhrase: 'Not Modified', Version: 1.1, Content: ,Headers:{} <<<< 这是 restApi 的正确响应吗?
R
Ramesh R

我想事实上的标准还没有真正出现(而且可能永远不会出现)。但无论如何,这是我的看法:

请求成功:

{
  "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"
}

优点:成功和错误情况下的顶级元素相同

缺点:没有错误代码,但是如果您愿意,您可以将状态更改为(成功或失败)代码,或者您可以添加另一个名为“代码”的顶级项目。


是的,如果您使用 POJO 进行 json 解析,这是正确的方法!当我们使用 POJO 时,我们需要静态的、非动态的 json 格式!
简单明了。在我看来比 jsend 更好,因为 jsend 区分错误和失败。
我也使用这种模式,但有一个名为 messages 的字段,它是一个 消息数组,而不是单个字符串。
答案几乎是有据可查的 JSend 的副本,它既简单又非常有用。他们为典型的验证问题提供了第三种状态 fail,而 error 仅用于诸如 db 错误之类的致命问题。
为了成功:如果标题中有 200,为什么还需要 status 字段?直接返回数据对象。你知道这可能会给 TypeScript 等类型化的 FE 语言带来额外的痛苦。
e
eugen

假设您的问题是关于 REST Web 服务设计,更准确地说是关于成功/错误。

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

仅使用 HTTP 状态代码来指示是否存在错误,并尝试将自己限制为标准状态代码(通常就足够了)。优点:它是独立于您的 api 的标准。缺点:关于真实情况的信息较少。使用 HTTP 状态 + json 正文(即使是错误)。为错误定义一个统一的结构(例如:代码、消息、原因、类型等)并将其用于错误,如果成功则只返回预期的 json 响应。优点:仍然是标准的,因为您使用现有的 HTTP 状态代码并返回描述错误的 json(您提供有关发生情况的更多信息)。缺点:输出 json 会因错误或成功而异。忘记 http 状态(例如:总是状态 200),总是使用 json 并在响应的根部添加一个布尔值 responseValid 和一个错误对象(代码、消息等),如果它是一个错误则将被填充,否则其他字段(成功)已填充。优点:客户端仅处理作为 json 字符串的响应主体并忽略状态(?)。缺点:标准较低。

由你来选择:)

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

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

编辑:

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

解决方案 3 在服务器端和客户端都很容易实现,但它不是很好,因为您必须将要返回的对象封装在一个包含 responseValid + 错误的响应对象中。


你说我应该“为错误定义一个统一的结构”和其他类似的建议,但这正是我要问的。我猜答案是“不,没有关于这种结构的标准或最佳实践”。
记录一下:HTTP 状态代码不是标头。
“响应将不是 json 而是 html。”错误的! html 与错误处理无关。响应可以是您支持的任何内容类型。
@アレックス HTTP 状态代码是 HTTP 响应标头状态行中的 3 位代码。该行之后是标题字段,俗称标题。
@アレックス HTTP 上的维基百科页面很好地回答了您的问题,您可以在那里查看:en.wikipedia.org/wiki/…(链接到响应消息部分)
B
Berislav Lopac

RFC 7807: Problem Details for HTTP APIs 是目前我们拥有的最接近官方标准的东西。


3年后……似乎是前进的方向。另请参阅:youtu.be/vcjj5pT0bSQ?t=611(Visual Studio .Net 核心支持 7807)
M
Muhammad Amin

以下是 Instagram 使用的 json 格式

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

2
2 revs

我不会傲慢地声称这是一个标准,所以我会使用“我更喜欢”的形式。

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

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

400 返回请求错误的消息:

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

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

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

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

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

理由:

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


“JSON 是一种有效载荷格式……”。不,JSON 是一种数据序列化格式。您可以使用它来传输您想要的任何内容,包括会话协议或只是简单的有效负载。您的 KISS 评论虽然是目标,但与 JSON 无关。最好让 JSON 专注于它是什么(如您所描述的成功数据或失败原因数据),而不是用一些混杂的东西来污染它,这些混杂的东西必须不断地组合起来,然后再被剥离出来。然后,您可以一直将 JSON 数据按原样存储在 Couchbase 中,然后按原样返回给应用程序。
也许我应该将其表述为“应该是有效载荷格式”,但除此之外,我坚持我的评论。您可以将会话/错误数据作为正文标记的属性放在 HTML 文档中,但这并不是正确或明智的做法。
r
robert_difalco

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

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

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

这里的重要一点是“字段”属性必须与无法验证的 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 对象本身的根中的数字错误代码。但到目前为止,我们还不需要它。


a
adnan kamili

他们对大型软件巨头——谷歌、Facebook、Twitter、亚马逊等的其余 api 响应格式没有一致意见,尽管上面的答案中提供了许多链接,其中一些人试图标准化响应格式。

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

以下是我对受谷歌、推特、亚马逊和互联网上一些帖子启发的响应格式的看法:

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

招摇文件:

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


支持无信封的 rest-api-response-format
@adnan kamilli -> > StatusCode:304,ReasonPhrase:'未修改',版本:1.1,内容:,Headers:{} <<<<这是restApi的正确响应吗?
@ArnoldBrown 对于哪个 API 端点-您要返回此代码的操作?
它是用于上传图像(表单数据)的 api 的响应返回 - 客户端编写的 api。
N
Norguard

JSON 的重点在于它是完全动态和灵活的。随心所欲地弯曲它,因为它只是一组序列化的 JavaScript 对象和数组,植根于单个节点。

根节点的类型取决于您,它包含的内容取决于您,是否将元数据与响应一起发送取决于您,是否将 mime-type 设置为 application/json 或将其保留为 {2 } 取决于你(只要你知道如何处理边缘情况)。

构建您喜欢的轻量级架构。就个人而言,我发现分析跟踪和 mp3/ogg 服务和图像库服务以及用于在线游戏的文本消息和网络数据包,以及博客文章和博客评论在什么方面都有非常不同的要求发送和接收什么以及如何使用它们。

因此,在做所有这些时,我最不想做的就是尝试使每个都符合相同的样板标准,该样板标准基于 XML2.0 或类似的东西。

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


感谢您的回复,但同样,我并不担心有效载荷本身。尽管您的示例在有效负载中发送/接收的内容以及这些有效负载的使用方式方面都有非常不同的要求,但它们都必须解决与响应本身相关的相同问题。即,他们都需要确定请求是否成功。如果是,则继续处理。如果不是,那么出了什么问题。这是我在我的问题中提到的所有 API 响应所共有的样板。
要么为所有内容返回 200 状态,并为自己定义一个特定的错误有效负载,要么返回与错误相称的状态,在有效负载主体中包含和/或不包含更多详细信息(如果支持)。就像我说的,模式由你决定——包括任何元/状态信息。这是一个 100% 的空白,可以根据您喜欢的建筑风格来做您喜欢的事情。
我意识到这是一张白纸,可以随心所欲。我的问题的目的是询问就结构而言是否有任何新兴标准。我不是在问“什么是 JSON 以及如何使用它”,而是“我知道如何使用 JSON 来返回/构造我想要的任何东西,但我想知道是否有任何标准结构正在使用或变得流行起来。”如果我的问题措辞有误,我很抱歉。无论如何,谢谢您的回复。
d
dnault

JSON-RPC 2.0 定义了标准的请求和响应格式,在使用 REST API 之后是一股清新的空气。


JSON-RPC_2.0 为异常提供的唯一东西是错误代码吗?数字错误代码不能以任何保真度表示发生的问题。
@AgilePro 同意,数字错误代码不是很好,我希望规范的作者允许 code 字段是字符串。幸运的是,规范允许我们将任何我们想要的信息填充到错误的 data 字段中。在我的 JSON-RPC 项目中,我通常使用单个数字代码来处理所有应用程序层错误(而不是标准协议错误之一)。然后我将详细的错误信息(包括一个指示真正错误类型的字符串代码)放在 data 字段中。
A
AgilePro

建议的基本框架看起来不错,但定义的错误对象太有限了。人们通常不能使用单个值来表达问题,而是使用 chain of problems and causes is needed

我做了一些研究,发现返回错误(异常)的最常见格式是这种形式的结构:

{
   "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 对象以及异常。

我在 Error Handling in JSON REST API 上的博文中讨论了详细信息


C
CodeBiker

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

JSON-LD,它是 W3C 推荐标准,指定如何在 JSON 中构建可互操作的 Web 服务

REST 的 Ion 超媒体类型,它声称自己是“一种简单直观的基于 JSON 的 REST 超媒体类型”


M
Mohammad Chehab

我曾经遵循这个标准,在客户端层非常好、简单、干净。

通常情况下,HTTP 状态 200,所以这是我在顶部使用的标准检查。我通常使用以下 JSON

我还使用 API 的模板

dynamic response;

try {
   // query and what not.
   response.payload = new {
      data = new {
          pagination = new Pagination(),
          customer = new Customer(),
          notifications = 5
      }
   }

   // again something here if we get here success has to be true
   // I follow an exit first strategy, instead of building a pyramid 
   // of doom.
   response.success = true;
}
catch(Exception exception){
   response.success = false;
   response.message = exception.GetStackTrace();
   _logger.Fatal(exception, this.GetFacadeName())
}

return response;

{ 
  "success": boolean,
  "message": "some message",
  "payload": { 
     "data" : []
     "message": ""
     ... // put whatever you want to here.
  } 
}

在客户端层我将使用以下内容:

if(response.code != 200) { 
  // woops something went wrong.
  return;
}

if(!response.success){
  console.debug ( response.message ); 
  return;
}

// if we are here then success has to be true.
if(response.payload) {
  ....
}

请注意我是如何早早打破厄运金字塔的。


B
Broken Arrow

除了常识,没有违法或违法的标准。如果我们将其抽象为两个人交谈,标准是他们可以在最短的时间内用最少的单词准确理解彼此的最佳方式。在我们的例子中,“最少词”是优化带宽以提高传输效率,“准确理解”是提高解析器效率的结构;最终导致数据越少,结构越通用;这样它就可以通过一个针孔并可以通过一个通用范围进行解析(至少在最初)。

几乎在所有建议的情况下,我都会看到“成功”和“错误”场景的不同响应,这对我来说有点模棱两可。如果这两种情况下的反应不同,那么为什么我们真的需要在那里放置一个“成功”标志呢?没有“错误”就是“成功”这不是很明显吗?是否可以在“成功”为 TRUE 并设置“错误”的情况下做出响应?或者,“成功”是假的,没有设置“错误”?一个flag还不够?我宁愿只使用“错误”标志,因为我相信“错误”会比“成功”少。

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


B
Benjamin Alijagić

我将此结构用于 REST API:

{
  "success": false,
  "response": {
    "data": [],
    "pagination": {}
  },
  "errors": [
    {
      "code": 500,
      "message": "server 500 Error"
    }
  ]
}

E
Ed Barahona

有点晚了,但这是我对 HTTP 错误响应的看法,我发送代码(通过状态)、通用消息和详细信息(如果我想提供特定端点的详细信息,有些是不言自明的,所以不需要详细信息但它可以是自定义消息,甚至可以是完整的堆栈跟踪,具体取决于用例)。为了成功,它是一个类似的格式、代码、消息和数据属性中的任何数据。

ExpressJS 响应示例:

// Error

    res
      .status(422)
      .json({
        error: {
          message: 'missing parameters',
          details: `missing ${missingParam}`,
        }
      });
        
    // or
        
    res
      .status(422)
      .json({
        error: {
          message: 'missing parameters',
          details: 'expected: {prop1, prop2, prop3',
        }
      });

 // Success

    res
      .status(200)
      .json({
         message: 'password updated',
         data: {member: { username }}, // [] ...
      });

M
Manish Vadher

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

这是为了“成功”响应

{  
   "code":"1",
   "msg":"Successfull Transaction",
   "value":"",
   "data":{  
      "EmployeeName":"Admin",
      "EmployeeID":1
   }
}

这是针对“错误”响应

{
    "code": "4",
    "msg": "Invalid Username and Password",
    "value": "",
    "data": {}
}

最好将您的属性标准化。它们都是“返回...”值。但是 Data 没有前缀。我会说,删除所有“返回”前缀。
包括“返回”也是相当多余的。