RESTful API中的错误的最佳实践

时间:2013-03-24 15:26:27

标签: php api rest laravel laravel-4

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

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

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

3 个答案:

答案 0 :(得分:12)

当你看list of available HTTP status codes时,你会在某些时候意识到它们有很多,但单独使用它们本身并不能真正解释错误。

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

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

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

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

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

请注意,还有更多的状态代码,其中一些与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

因此,您希望客户端发送Accept: application/vnd.IAMVENDOR.MYAPI-v1+json标头,而不是将版本放在网址中,您也可以使用Content-type: application/vnd.IAMVENDOR.MYAPI-v1+json进行回复。对于第一个版本,这确实没有任何改变,但让我们看看第2版发挥作用时的情况。

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

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

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

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

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

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

答案 1 :(得分:2)

我不会为所有事情使用200状态。那只是令人困惑。

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

编辑: 另外,我强烈建议您观看有关Laravel和API开发的讨论:

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

答案 2 :(得分:1)

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

例如:

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

更具可读性。