REST API错误代码返回结构



我正在编写一个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响应应该是什么样子的,我想到了以下选项:

  1. 在第一次遇到错误时停止,并返回带有特定错误代码的响应

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

在我看来,选项2是正确的方式(它为开发人员/最终用户提供了更多有用的信息,服务器负载可能更低(请求更少/无需重新验证有效数据/无需计算签名和验证用户),但我正在探索最佳实践是什么,以及是否有其他方法来处理这类问题。

此外,我认为如果在脚本流中出现一个致命错误,选项1仍然有效。(不是验证错误)

请注意,代码只是一个简单的数组,因此更容易理解。响应格式将为JSON或XML。

让我们看看Facebook的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响应制定了一些规则。"他们的目标是:

有很多web服务提供JSON数据,每种服务都有自己的格式化响应的方式。此外,为JavaScript前端编写代码的开发人员不断地重新发明从服务器通信数据的轮子。虽然结构化这些数据有很多常见的模式,但在命名或响应类型等方面却没有一致性。此外,这有助于促进后端开发人员和前端设计师之间的快乐和团结,因为每个人都可以期待一种共同的交互方法。

以下是错误消息示例:

{
    "status" : "fail",
    "data" : { "title" : "A title is required" }
}

看起来脸书和这个试图制定行业标准的团体选择了你的选择#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"
    }
  ]
}

我自己也用过几次#2。它比#1好吗?我认为这取决于你的API的用途。

我喜欢#2,因为它让正在用一些测试调用测试API的开发人员快速了解他在请求中所犯的所有错误,这样他就可以立即知道必须修复哪些错误才能使请求有效。如果你一个接一个地返回错误(如#1),你必须不断重试请求,并祈祷它这次有效。

但正如我所说,#2对开发人员非常有用,但其原因并不真正适用于最终用户。最终用户通常不关心它是如何实现的。软件是执行返回5个错误的1个请求,还是执行每个返回1个错误的5个后续请求
只要它在客户端中处理得很好,最终用户就不应该注意到差异。当然,如何处理这在很大程度上取决于客户端的实际是什么

除了加快开发之外,#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响应,状态代码不应该放在正文中,而应该放在头中。这意味着CCD_ 1和CCD_。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"
    }
]

所以现在剩下的只是一个错误列表。

状态代码在响应标头中指定
详细信息在响应正文中指定。

我最近使用了一个Rest API,该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""
           }
      }
  }

这将使您能够提供结果,并根据需要在响应中提供多个警告或错误。

是的,这在结构上确实有一些膨胀,但它也为开发人员提供了一个简单的接口,让他们总是在同一结构中获取数据。

我还将删除以下项目作为IMHO,它们应该在API文档中(如何使用错误代码找到帮助),而不是在每个错误上:

"more_info": "www.api.com/help/errors/2"
"more_info": "www.api.com/help/errors/3"

同样,我不确定您是否同时需要message和developer_message。它们似乎是多余的,并且当调用方未能正确提供数据时,就好像您试图从API提供用户错误消息。

首先,您将为客户提供Rest API方法的文档。因此,客户/开发人员需要为参数提供有效的数据。

现在已经说过#1是做Rest API的最佳方式。开发人员的责任是最大限度地减少服务器的使用。因此,如果您遇到任何致命错误,请用相应的错误代码和错误消息构建一个响应并返回

此外,我们不能确定在我们遇到的错误之后还会有更多的错误。因此,解析其余的数据是没有意义的。考虑到最坏的情况,它不会很好地工作。

就我个人而言,我会减少用户的详细信息,并在数据库日志表或系统日志中向开发人员转储所需的错误。由于您使用的是JSON,这在Apache服务器上最常见,您的代码看起来可能是php(但您的大括号代码示例可能是源自PASCAL的多种语言,例如C、C#PERL、php、CSharp)。如果您还不知道如何在php中输出自定义错误,下面是如何将其放入系统日志http://php.net/manual/en/function.syslog.php。如果您使用的是带有JSON和CSharp的罕见配置IIS,那么也有.NET库可以做类似的事情。如果你在错误发生时向用户提供了太多信息,那么你也为未来的黑客提供了一种探测你网站的方法。

API不适用于人类。因此,您不需要返回详细的错误文本。您甚至可以返回一个错误代码,意思是"缺少参数"。只是别忘了把它记录好。

最新更新