我正在编写一个REST API,我偶然发现了一个问题。返回验证错误的最佳方法是什么。
到目前为止,我一直在将转储的错误消息返回到一般错误代码中(例如,假设请求不好)
{
"status": 400,
"error": {
"code": 1, // General bad request code
"message": [
"The Key \"a\" is missing",
"The Key \"b\" is missing",
"The Key \"c\" is missing",
"Incorrect Format for field \"y\""
]
}
)
我已经研究了一些关于良好的API响应应该如何的样子,我想到了以下几个选项:
在遇到第一个错误时停止并返回具有特定错误代码的响应
{
"status": 400, //Same as the HTTP header returned
"error" {
"code": 1, // Specific field validation error code
"message": "Field \"x\" is missing from the array structure",
"developer_message": "The request structure must contain the following fields {a,b,c{x,y,z}}",
"more_info" => "www.api.com/help/errors/1"
}
)
解析所有请求数据并返回多个字段验证错误。
{
"status": 400,
"error": {
"code": 1 //General bad Request code
"message": "Bad Request",
"developer_message": "Field validation errors."
"more_info": "www.api.com/help/errors/1",
"error_details": {
0: {
"code": 2 // Specific field validation error code
"message": "Field \"x\" is missing from the array structure",
"developer_message": "The request structure must contain the following fields {a,b,c{x,y,z}}",
"more_info": "www.api.com/help/errors/2"
},
1: {
"code": 3 // Specific field validation error code
"message": "Incorrect Format for field \"y\"",
"developer_message": "The field \"y\" must be in the form of \"Y-m-d\"",
"more_info": "www.api.com/help/errors/3"
}
}
}
}
在我看来,选项2将是正确的方式(它为开发人员/最终用户提供更多有用的信息,服务器负载可能更低(更少的请求/不需要重新验证有效数据/不需要计算签名和验证用户)),但我在徘徊什么是最佳实践,如果有另一种方法来处理这类问题。
此外,我认为如果我在脚本流程中遇到单个致命错误,则选项1仍然有效。(不是验证错误)
请注意,代码只是一个简单的数组,因此更容易理解。响应格式为JSON或XML。
答案 0 :(得分:21)
让我们看看Facebook's Graph API。这很难受,很有可能产生很多错误。这是Facebook在API错误上返回的内容:
{
"error": {
"message": "Message describing the error",
"type": "OAuthException",
"code": 190,
"error_subcode": 460,
"error_user_title": "A title",
"error_user_msg": "A message"
}
}
他们尝试使Graph API尽可能有用,但它们似乎返回了代码和子代码(Ref)的特定错误。每个错误都有自己的代码这一事实意味着更容易搜索所述代码或消息作为调试的起点。这可能就是为什么他们不会在官方错误响应中累积错误消息。如果它足够好并且方便Facebook,那对我们来说可能已经足够了。
示例错误回复:
{
"error": {
"message": "(#200) Must have a valid access_token to access this endpoint",
"type": "OAuthException",
"code": 200
}
}
和
"error": {
"message": "(#604) Your statement is not indexable. The WHERE clause must contain
an indexable column. Such columns are marked with * in the tables linked from
http://developers.facebook.com/docs/reference/fql ",
"type": "OAuthException",
"code": 604
}
然后有JSend“这是一个规范,规定了如何格式化来自Web服务器的JSON响应的规则。”他们的目标是:
有许多提供JSON数据的Web服务,每种都有自己的格式化响应方式。此外,为JavaScript前端编写的开发人员不断重新发明从服务器传输数据的方法。虽然有许多用于构造此数据的常见模式,但在命名或响应类型等方面没有一致性。此外,这有助于促进后端开发人员和前端设计人员之间的快乐和团结,因为每个人都可以期待一种共同的方法来相互交流。
以下是示例错误消息:
{
"status" : "fail",
"data" : { "title" : "A title is required" }
}
看起来Facebook和这个试图像行业标准设定的群体选择了你的选择#1。
为了回应“如果有人去过#2且可能有任何改进吗?”的赏金请求,Pragmatic RESTful API的设计模式表明:
验证错误需要现场细分。最好使用固定的顶级错误代码进行验证失败,并在其他错误字段中提供详细错误,如下所示:
{
"code" : 1024,
"message" : "Validation Failed",
"errors" : [
{
"code" : 5432,
"field" : "first_name",
"message" : "First name cannot have fancy characters"
},
{
"code" : 5622,
"field" : "password",
"message" : "Password cannot be blank"
}
]
}
答案 1 :(得分:3)
我自己曾经使用过#2次。它比#1好吗?我认为这取决于您的API用途。
我喜欢#2,因为它让正在测试API的开发人员通过一些测试调用快速概述了他在请求中所犯的所有错误/错误,因此他立即知道他必须修复哪些错误/错误该请求有效。如果你一个接一个地返回错误(比如在#1中),你必须继续重试请求并交叉手指,希望这次它有效。
但正如我所说,#2对开发人员非常有用,但其原因并不适用于最终用户。最终用户通常不关心它是如何实现的。软件是否正在执行1个返回5个错误的请求或5个后续请求,每个请求返回1个错误 只要它在客户端处理得很好,最终用户就不会注意到差异。当然,如何处理这取决于客户实际 的内容。
除了加速开发之外,#2(生产中)的另一个好处是它需要的请求更少,这当然会减少服务器负载。
我想知道是否有人去了#2并且可能有任何改进,所以我开了一笔赏金。
当然有待改进。实际上,身体中有一些数据可以省略。
{
"status": 400,
"error": {
"code": 1 //General bad Request code
"message": "Bad Request",
"developer_message": "Field validation errors."
"more_info": "www.api.com/help/errors/1",
"error_details": {
0: {
"code": 2 // Specific field validation error code
"message": "Field \"x\" is missing from the array structure",
"developer_message": "The request structure must contain the following fields {a,b,c{x,y,z}}",
"more_info": "www.api.com/help/errors/2"
},
1: {
(
"code": 3 // Specific field validation error code
"message": "Incorrect Format for field \"y\"",
"developer_message": "The field \"y\" must be in the form of \"Y-m-d\"",
"more_info": "www.api.com/help/errors/3"
)
}
)
使用HTTP响应时,状态代码不应该在正文中,而是在标题中。这意味着此处可以省略"status": 400
和"message": "Bad Request"
。 400应该是响应的状态代码,400表示错误请求。它是HTTP标准,无需在响应中进行说明。另外"developer_message": "Field validation errors."
有点重复,因为特定错误已经包含在每个单独的错误中,所以我们可以将其删除。
离开
{
"error": {
"code": 1 //General bad Request code
"more_info": "www.api.com/help/errors/1",
"error_details": {
0: {
"code": 2 // Specific field validation error code
"message": "Field \"x\" is missing from the array structure",
"developer_message": "The request structure must contain the following fields {a,b,c{x,y,z}}",
"more_info": "www.api.com/help/errors/2"
},
1: {
(
"code": 3 // Specific field validation error code
"message": "Incorrect Format for field \"y\"",
"developer_message": "The field \"y\" must be in the form of \"Y-m-d\"",
"more_info": "www.api.com/help/errors/3"
)
}
)
"code": 1 //General bad Request code
"more_info": "www.api.com/help/errors/1",
这两行现在不再有意义了。它们也不是必需的,因为每个错误都有它自己的代码和信息链接,所以我们也可以删除这些行,留下这个
{
"error": {
"error_details": {
0: {
"code": 2 // Specific field validation error code
"message": "Field \"x\" is missing from the array structure",
"developer_message": "The request structure must contain the following fields {a,b,c{x,y,z}}",
"more_info": "www.api.com/help/errors/2"
},
1: {
(
"code": 3 // Specific field validation error code
"message": "Incorrect Format for field \"y\"",
"developer_message": "The field \"y\" must be in the form of \"Y-m-d\"",
"more_info": "www.api.com/help/errors/3"
)
}
)
400状态代码已经表明存在错误,因此您不必再指示"error": {error details}
,因为我们已经知道存在错误。错误列表可以简单地成为根对象:
[
{
"code": 2//Specificfieldvalidationerrorcode
"message": "Field \"x\" is missing from the array structure",
"developer_message": "The request structure must contain the following fields {a,b,c{x,y,z}}",
"more_info": "www.api.com/help/errors/2"
},
{
"code": 3//Specificfieldvalidationerrorcode
"message": "Incorrect Format for field \"y\"",
"developer_message": "The field \"y\" must be in the form of \"Y-m-d\"",
"more_info": "www.api.com/help/errors/3"
}
]
所以现在剩下的只是一个错误列表。
状态代码在响应标题中指定 详细信息在响应正文中指定。
答案 2 :(得分:1)
我最近使用了Rest API,它会在结果中返回多个警告或错误。从样品#2开始,我将按如下方式对其进行修改:
{
"status": 400,
"results" : null,
"warnings": {
0: {
// Build a warning message here, sample text to show concept
"code": 1 // Specific field validation error code
"message": "It is no longer neccessary to put .js on the URL"
}
}
"errors": {
0: {
"code": 2 // Specific field validation error code
"message": "Field \"x\" is missing from the array structure"
"developer_message": "The request structure must contain the following fields {a,b,c{x,y,z}}",
},
1: {
"code": 3 // Specific field validation error code
"message": "Incorrect Format for field \"y\"",
"developer_message": "The field \"y\" must be in the form of \"Y-m-d\""
}
}
}
这将使您能够提供结果,并在响应中根据需要提供多个警告或错误。
是的,这确实在结构中有一些膨胀,但它也为开发人员提供了一个简单的界面,可以始终将他们的数据恢复到相同的结构中。
我还会删除以下项目,因为它们应该在API文档中(如何使用错误代码查找帮助)而不是每个错误:
"more_info": "www.api.com/help/errors/2"
"more_info": "www.api.com/help/errors/3"
同样,我不确定你是否需要消息和developer_message。它们似乎是多余的,并且当调用者无法正确提供数据时,您似乎试图从API提供用户错误消息。
答案 3 :(得分:0)
首先,您可以为客户提供Rest API方法的文档。因此,客户/开发人员希望为参数提供有效数据。
现在说#1是做Rest API的最佳方式。开发人员的职责是尽可能减少服务器的使用。因此,如果遇到任何致命错误,请使用相应的错误代码和错误消息构造响应并将其返回。
此外,我们无法确定在遇到错误后会有更多错误。因此解析其余数据毫无意义。考虑到最坏的情况,它不会很好。
答案 4 :(得分:-1)
就个人而言,我会给用户更少的细节,并在数据库日志表或系统日志中转储开发人员所需的错误。由于您使用的是JSON,这在Apache服务器上最常见,而您的代码看起来可能是php(但是您的代码示例带有大括号可能是源自PASCAL的多种语言,例如.C,C#PERL,PHP, CSHARP)。如果你还不知道php http://php.net/manual/en/function.syslog.php中的输出,那么如何将输出自定义错误放到系统日志中。如果您使用的是带有JSON和CSharp的稀有配置IIS,那么.NET库也可以执行类似操作。如果您在发生错误时向用户提供过多信息,那么您将来也会以黑客的方式探测您的网站。
答案 5 :(得分:-2)
API不适用于人类。因此,您无需返回详细的错误文本。您甚至可以返回错误代码,这意味着“缺少参数”。只是不要忘记记录好。