2013-03-24 91 views
9

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

在出现错误的情况下,应该使用

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

包括标志success

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

使用200而不是4XX,依靠success,以确定是否有错误

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

而在成功的情况下,也没有必要返回任何数据,你还回什么?

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? 
    } 
} 

回答

12

当你看list of available HTTP status codes,你会在某个时刻认识到,有很多人,但单独使用本身也不能真正解释错误。

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

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

这后一部分实际上比一件事情更难。有404个明显的情况用于告诉“未找到”。而500是服务器端的任何错误。

我不会使用状态401,除非我真的想让操作在存在HTTP身份验证凭证的情况下成功。 401通常会在浏览器中触发一个对话框,这很糟糕。

如果资源是唯一且已存在的,状态“409 Conflict”似乎是合适的。如果创建用户成功,状态“201 Created”听起来也是一个好主意。

请注意,还有更多的状态代码,其中一些与HTTP协议的扩展(如DAV)有关,一些完全没有标准化(例如状态“420让你的冷静”从Twitter API中获益)。看看http://en.wikipedia.org/wiki/List_of_HTTP_status_codes看看到目前为止使用了什么,然后决定是否要使用适合您的错误情况的东西。

根据我的经验,简单地选择一个状态码并使用它是很容易的,但很难一致地按照现有标准进行操作。

我不会因为别人会抱怨而停下来。 :)正确的做RESTful接口本身就是一项艰巨的任务,但接口越多,获得的经验就越多。

编辑:

关于版本的:它被认为是不好的做法,把一个版本标记到URL,像这样:example.com/api/v1/stuff它会工作,但它是不是很好。

但首先是:您的客户如何指定他想要获得哪种表示形式,即他如何决定要么获取JSON或XML?答案:Accept标题。他可以为JSON发送Accept: application/json,为XML发送Accept: application/xml。他甚至可能接受多种类型,并且服务器决定返回什么。

除非服务器被设计为回答多个资源表示(JSON或XML,客户端选择),否则客户端的确没有多少选择。但让客户至少发送“application/json”作为他的唯一选择,然后返回标题Content-type: application/json作为回应,这仍然是件好事。这样,双方都明确表示他们希望对方看到内容。

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

因此,当您创建使用JSON的API时,您不会处理泛型JSON。你处理一个具体的JSON结构,它对你的API来说是独一无二的。您可以也可能应该在服务器发送的Content-type中指出这一点。 “供应商”的扩展是这样的:Content-type: application/vnd.IAMVENDOR.MYAPI+json会告诉世界,基本的数据结构是application/json,但它是你的公司和你的API,真正地告诉哪个结构期望。而这正是API请求的版本适合的地方:application/vnd.IAMVENDOR.MYAPI-v1+json

因此,不要将版本放入URL中,而是期望客户端发送Accept: application/vnd.IAMVENDOR.MYAPI-v1+json标题,并且您也以Content-type: application/vnd.IAMVENDOR.MYAPI-v1+json作为响应。这对第一个版本确实没有什么影响,但让我们看看版本2发挥作用时的情况。

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

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

对版本使用accept标头时,资源的URL对于所有版本都是相同的。客户端决定使用版本1或2请求资源,服务器可能如此友善,仍然可以回答版本1请求的版本1响应,但所有版本2的请求都带有新的闪亮的版本2响应。

如果服务器无法应对版本1请求,他可以通过发送HTTP状态“406不可接受”来告诉客户端(请求的资源只能根据发送的接受头文件生成不可接受的内容请求。)

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

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

+0

restful api只是为我自己的网站的ajax/backbonejs/jquery使用。在这种情况下,我应该坚持相同的错误代码(比如400)吗?或者为每个AJAX响应返回200,并检查'success'变量以查看是否发生错误 – Nyxynyx 2013-03-24 15:50:03

+1

不,通过错误代码指示基本的“成功/错误”事实是一个非常好的主意。错误响应由HTTP客户端处理,例如,它们不应该被缓存等。在数据有效载荷内指示相同也是一件好事。我自己的API在成功时有“数据”,或者在失败时有“错误”。这与“成功=真/假”基本相同,并且适用于我。但是确实知道状态“400错误请求”不是您认为的通用客户端错误状态。没有这样的事情,你必须指定错误状态。 – Sven 2013-03-24 16:28:24

+2

很好的答案,斯文! 但是,您会说:>关于版本控制:将版本 >标记放入我不同意的网址中被认为是不好的做法。这是Apigee的一个[指南](http://apigee.com/about/api-best-practices/restful-api-design-second-edition),他得出结论认为* *确实是最佳的使用版本号的做法网址。他们还澄清了返回状态代码。 – unicopter 2013-04-10 19:27:14

2

我不会使用200状态的一切。这只会让人困惑。

Jquery允许您以不同的方式处理不同的响应代码,已经有内置的方法可以利用它们在您的应用程序中使用它们,当您的应用程序增长时,您可以提供该API供其他人使用。

编辑: 此外,我强烈建议看这个讲Laravel和API开发:

http://kuzemchak.net/blog/entry/laracon-slides-and-video

+0

视频链接很有帮助,但是演讲者在实现RESTful API时会做一些不好的事情,比如在URL中包含版本号。这就是“接受”标题的用途。 – Sven 2013-03-24 16:49:03

+0

@Sven你能否详细解释一下如何使用它?我很好奇=) – msurguy 2013-03-24 21:29:27

+0

更新了我的答案。 – Sven 2013-03-25 00:32:32

1

有在Illuminate\Http\Response HTTP状态代码的一些列表扩展到Symfony\Component\HttpFoundation\Response。你可以在你的课堂上使用它。

例如:

use Illuminate\Http\Response as LaravelResponse; 
... 
return Response::json('User Exists', LaravelResponse::HTTP_CONFLICT); 

它更具有可读性。