RESTful API 错误的最佳实践 [英] Best Practice for Errors in RESTful API

查看:50
本文介绍了RESTful API 错误的最佳实践的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 RESTful API 中返回 HTTP 状态代码的最佳实践是什么?我的 PHP 框架使用 Laravel 4.

What are the best practices for returning HTTP status codes in RESTful API? I am using Laravel 4 for my PHP framework.

如果出现错误,我应该使用

In the case of an error, should I use

return Response::json('User Exists', 401);

包含 success

return Response::json([
    'success' => false,
    'data' => 'User Exists'],
    401
);

使用200代替4xx,依靠success判断是否有错误

use 200 instead of 4xx, relying on success to determine if there is an error

return Response::json([
    'success' => false,
    'data' => 'User Exists'],
    200
);

而且在成功不需要返回任何数据的情况下,你还返回什么吗?

And in the case of success and there is no need to return any data, do you still return anything?

PHP API 代码

public function getCheckUniqueEmail() {
    // Check if Email already exist in table 'users'
    $uniqueEmail = checkIfEmailExists();

    // Return JSON Response
    if($uniqueEmail) {
        // Validation fail (user exists)
        return Response::json('User Exists', 401);
    } else {
        // Validation success
        // - Return anything?
    }
}

推荐答案

当你查看 可用的 HTTP 状态代码列表,您有时会意识到它们有很多,但单独使用它们本身并不能真正解释错误.

When you look at the list of available HTTP status codes, you will at some point realize that there are plenty of them, but used alone they cannot really explain an error by itself.

所以要回答你的问题,有两个部分.一个是:您的 API 如何传达错误原因并添加 API 用户(在大多数情况下是另一位开发人员)可以阅读和采取行动的有用信息.您应该添加尽可能多的信息,包括机器可读和人类可读.

So to answer your question, there are two parts. One is: How can your API communicate the reasons for an error and add useful information that the user of the API (which in most cases is another developer) can read and act upon. You should add as much information as possible, both machine readable and human readable.

另一部分:HTTP 状态代码如何帮助区分某些错误(和成功)状态?

The other part: How can HTTP status codes help in distinguish certain error (and success) states?

后一部分实际上比一件事情更难.在明显的情况下,404 用于告诉未找到".对于服务器端的任何错误,500.

This latter part is actually harder than one might thing. There are the obvious cases where 404 is used to tell "not found". And 500 for any errors that are server-side.

我不会使用状态 401,除非我真的希望在存在 HTTP 身份验证凭据的情况下允许操作成功.401 通常会在浏览器中触发一个对话框,这是不好的.

I wouldn't use status 401, unless I really want to allow the operation to succeed if there are HTTP authentication credentials present. 401 usually triggers a dialog box in the browser, which is bad.

如果资源是唯一的并且已经存在,状态409 冲突"似乎是合适的.如果创建用户成功,状态201 Created"听起来也是个好主意.

In case of a ressource being unique and already existing, status "409 Conflict" seems appropriate. And if creating a user succeeds, status "201 Created" sounds like a good idea, too.

请注意,还有更多的状态代码,其中一些与 HTTP 协议的扩展有关(如 DAV),一些完全未标准化(如 Twitter API 中的状态420 增强您的冷静").看看 http://en.wikipedia.org/wiki/List_of_HTTP_status_codes 看看有什么到目前为止已经使用过,并决定是否要使用适合您的错误情况的东西.

Note that there are a lot more status codes, some of them related to extensions of the HTTP protocol (like DAV), some completely unstandardized (like status "420 Enhance your calm" from the Twitter API). Have a look at http://en.wikipedia.org/wiki/List_of_HTTP_status_codes to see what has been used so far, and decide whether you want to use something appropriate for your error cases.

根据我的经验,简单地选择一个状态代码并使用它很容易,但很难按照现有标准一致地这样做.

From my experience, it is easy to simply pick a status code and use it, but it is hard to do so consistently and in accordance with existing standards.

然而,我不会仅仅因为其他人可能会抱怨而停在这里.:) 做好 RESTful 接口本身就是一项艰巨的任务,但接口越多,积累的经验也就越多.

I wouldn't however stop here just because others might complain. :) Doing RESTful interfaces right is a hard task in itself, but the more interfaces exists, the more experience has been gathered.

关于版本控制:将版本标记放入 URL 被认为是不好的做法,如下所示:example.com/api/v1/stuff 它可以工作,但不是很好.

Regarding versioning: It is considered bad practice to put a version tag into the URL, like so: example.com/api/v1/stuff It will work, but it isn't nice.

但第一件事是:您的客户如何指定他想要获得哪种表示,即他如何决定获得 JSON 或 XML?答案:使用 Accept 标头.他可以为 JSON 发送 Accept: application/json,为 XML 发送 Accept: application/xml.他甚至可能接受多种类型,然后由服务器决定返回什么.

But the first thing is: How does your client specify which kind of representation he wants to get, i.e. how can he decide to either get JSON or XML? Answer: With the Accept header. He could send Accept: application/json for JSON and Accept: application/xml for XML. He might even accept multiple types, and it is for the server to decide then what to return.

除非服务器被设计为用一种以上的资源表示(JSON 或 XML,客户端选择)来回答,否则客户端真的没有太多选择.但是让客户端至少发送application/json"作为他唯一的选择,然后返回一个标头 Content-type: application/json 作为响应仍然是一件好事.这样,双方都清楚他们希望对方看到什么样的内容.

Unless the server is designed to answer with more than one representation of the resource (JSON or XML, client-selected), there really isn't much choice for the client. But it still is a good thing to have the client send at least "application/json" as his only choice and then return a header Content-type: application/json in response. This way, both sides make themselves clear about what they do expect the other side to see the content like.

现在是版本.如果您将版本放入 URL,您可以有效地创建不同的资源(v1 和 v2),但实际上您只有一种资源(= URL),可以使用不同的方法访问它.当请求的参数和/或响应中的表示与当前版本不兼容时,必须创建新版本的 API.

Now for the versions. If you put the version into the URL, you effectively create different resources (v1 and v2), but in reality you have only one resource (= URL) with different methods to access it. Creating a new version of an API must take place when there is a breaking change in the parameters of a request and/or the representation in the response which is incompatible with the current version.

因此,当您创建使用 JSON 的 API 时,您无需处理通用 JSON.您处理一个具体的 JSON 结构,该结构对您的 API 来说是独一无二的.您可以并且可能应该在服务器发送的 Content-type 中指明这一点.供应商"扩展名就是为了这个:Content-type: application/vnd.IAMVENDOR.MYAPI+json 会告诉全世界基本数据结构是 ap​​plication/json,但它是你的公司和您的 API 真正说明了预期的结构.这正是 API 请求版本适合的地方:application/vnd.IAMVENDOR.MYAPI-v1+json.

So when you create an API that uses JSON, you do not deal with generic JSON. You deal with a concrete JSON structure that is somehow unique to your API. You can and probably should indicate this in the Content-type sent by the server. The "vendor" extension is there for this: Content-type: application/vnd.IAMVENDOR.MYAPI+json will tell the world that the basic data structure is application/json, but it is your company and your API that really tells which structure to expect. And that's exactly where the version for the API request fits in: application/vnd.IAMVENDOR.MYAPI-v1+json.

因此,您希望客户端发送一个 Accept: application/vnd.IAMVENDOR.MYAPI-v1+json 标头,而不是将版本放在 URL 中,然后您用 Content 进行响应-type: application/vnd.IAMVENDOR.MYAPI-v1+json 也是如此.这对于第一个版本确实没有任何改变,但是让我们看看当第 2 版开始使用时事情会如何发展.

So instead of putting the version in the URL, you expect the client to send an Accept: application/vnd.IAMVENDOR.MYAPI-v1+json header, and you respond with Content-type: application/vnd.IAMVENDOR.MYAPI-v1+json as well. This really changes nothing for the first version, but let's see how things develop when version 2 comes into play.

URL 方法将创建一组完全不相关的新资源.客户端会想知道 example.com/api/v2/stuff 是否与 example.com/api/v1/stuff 是相同的资源.客户端可能已经使用 v1 API 创建了一些资源,并且他存储了这些东西的 URL.他应该如何将所有这些资源升级到v2?资源真的没变,都是一样的,唯一变了就是在v2中看起来不一样了.

The URL approach will create a completely unrelated set of new resources. The client will wonder if example.com/api/v2/stuff is the same resource as example.com/api/v1/stuff. The client might have created some resources with the v1 API and he stored the URLs for this stuff. How is he supposed to upgrade all these resources to v2? The resources really have not changed, they are the same, the only thing that changed is that they look different in v2.

是的,服务器可能会通过发送到 v2 URL 的重定向来通知客户端.但是重定向并不表示客户端也必须升级 API 的客户端部分.

Yes, the server might notify the client by sending a redirect to the v2 URL. But a redirect does not signal that the client also has to upgrade the client part of the API.

当使用带有版本的接受标头时,资源的 URL 对于所有版本都是相同的.客户端决定使用版本 1 或 2 请求资源,服务器可能非常友好并且仍然使用版本 1 响应来响应版本 1 请求,但是所有版本 2 请求都使用新的和闪亮的版本 2 响应.

When using an accept header with the version, the URL of the resource is the same for all versions. The client decides to request the resource with either version 1 or 2, and the server might be so kind and still answers version 1 requests with version 1 responses, but all version 2 requests with the new and shiny version 2 responses.

如果服务器无法响应版本 1 的请求,他可以通过发送 HTTP 状态406 Not Acceptable"来告诉客户端(根据请求中发送的 Accept 头,请求的资源只能生成不可接受的内容)请求.)

If the server is unable to answer to a version 1 request, he can tell the client by sending HTTP status "406 Not Acceptable" (The requested resource is only capable of generating content not acceptable according to the Accept headers sent in the request.)

客户端可以发送包含两个版本的接受头,这使服务器能够用他最喜欢的一个响应,即智能客户端可能实现版本 1 和 2,现在将两者都作为接受头发送,并等待服务器从版本 1 升级到 2.服务器会在每个响应中告诉它是版本 1 还是 2,客户端可以相应地采取行动 - 他不需要知道服务器版本升级的确切日期.

The client can send the accept header with both versions included, which enabled the server to respond with the one he likes most, i.e. a smart client might implement versions 1 and 2 and now sends both as accept header, and waits for the server to upgrade from version 1 to 2. The server will tell in every response whether it is version 1 or 2, and the client can act accordingly - he does not need to know the exact date of the server version upgrade.

总结一下:对于一个非常基本的 API 来说,它可能是内部的,即使有一个版本也可能是过度使用.但你永远不知道一年后这是否会成为现实.在 API 中包含版本号总是一个很好的主意.最好的地方是在您的 API 即将使用的 MIME 类型中.检查单个现有版本应该很简单,但您可以选择稍后透明升级,而不会混淆现有客户端.

To sum it up: For a very basic API with limited, maybe internal, usage even having a version might be overkill. But you never know if this will be true a year from now. It is always a very good idea to include a version number into an API. And the best spot for this is inside the mime type that your API is about to use. Checking for the single existing version should be trivial, but you have the option of transparently upgrading later, without confusing existing clients.

这篇关于RESTful API 错误的最佳实践的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆