Best practices for REST API design - Stack Overflow
REST API 是最常见的 Web 服务类型之一。浏览器、应用程序等各种客户端 都可以通过 REST API与服务器通信。
正确设计 REST API 非常重要, 我们要考虑 REST API 的安全性、性能和易用性。
什么是 REST API
REST API 是一种应用程序编程接口, 它符合特定的体系结构约束,如无状态通信和可缓存数据。它不是协议或标准。
虽然 REST API 可以通过多种通信协议进行访问,但最常见的是通过 HTTPS 。
以下准则适用于将通过 Internet 调用的 REST API 端点。
注意:对于通过互联网调用的 REST API,您需要遵循 REST API 身份验证的最佳实践。
使用 JSON 作为输入和响应
REST API 应以 JSON 作为数据传输标准:
- 接受 JSON 作为请求负载
- 通过 JSON 发送响应。
JSON 是传输数据的标准,无论是客户端还是服务器端,使用JSON都很方便。
表单比较适合发送文件。但对于文本和数字,我们可以直接在客户端从中获取JSON传输。这样最直接。
在返回JSON时,应该设置响应标头,`Content-Type: application/json`。不过很多库会自动替我们设置这个标头。
在路径中使用名词而不是动词
我们不应该在端点路径中使用动词。相反,应该使用相关实体的名词,作为路径名。
这是因为我们的 HTTP 请求方法已经具有动词。在我们的 API 终结点路径中使用动词是没有用的。它不传达任何新信息,只是显得冗长,而且,所选动词可能因开发人员的心血来潮而异。例如,有人用“get”,有人用“retrieve”。
所以最好让HTTP GET动词告诉我们和端点的作用。
最常用的方法包括 GET、POST、PUT 和 DELETE。
- GET 检索资源。
- POST 将新数据提交到服务器。
- PUT 会更新现有数据。
- DELETE 删除数据。
动词映射到 CRUD 操作。比如:
- GET /articles 获得取文章列表
- GET /articles/:id 获得某篇文章
- POST /articles 创建新文章
- PUT /articles/:id 修改某篇文章
- DELETE /articles/:id 删除某篇文章
在路径中使用资源嵌套
在实际中,一个资源可能包含其它资源,比如一篇文章可能包含多个评论。我们要设计合理的路径来表示这种嵌套。
注意:REST API 路径中的资源嵌套最好不要照搬数据库的表结构,以免后台数据结构的泄露。
比如,GET /articles/:articleId/comments 得到某篇文章的所有评论。
然而,这种嵌套可能有很多层,尤其在二三层之后,这种结构就会变得很笨拙。这时候,就可以通过返回对象的URL 来终止这种嵌套。
比如:你想得到某篇文章的某个评论的作者,与其返回某个 articleId 中大而全的结构,不如在 /articles/:articleId/comments/:commentId/author 中直接返回 URI "author": "/users/:userId"
这个,客户端在拿到地址之后,可以再根据接口,拉取更详细的信息。避免一次查询过于臃肿。
优雅地处理错误 - 返回有效的信息
API 出错可能有多种情况,但我们可以把出错分为两大类:
- HTTP 协议级出错
- 上层应用逻辑出错
周全考虑,我们应该返回 HTTP 返回码和应用逻辑状态码。HTTP 返回码通常是标准的,而应用逻辑状态码需要我们自己约定。
使用 HTTP 标准返回码
常见的 HTTP 状态码包括:
- 200 OK - HTTP 请求正常
- 400 BAD REQUEST - 请求的参数格式错误
- 401 UNAUTHORIZE - 认证未通过(比如用户名密码错,导致不能通过认证)
- 403 FORBBIDEN - 没有授权
- 404 NOT FOUND - 找不到资源,这个有时候会被电信运营商劫持
- 500 INTERNAL SERVER ERROR - 通用的服务器内部错误
- 502 BAD GATEWAY - 上游服务出错
- 503 SERVICE UNAVAILABLE - 服务不可用
还应加上应用状态信息
除了认真返回 HTTP 状态码之外,我们还应该在返回内容中增加 err 部分,添加更细致的返回/出错状态信息。
比如,数据库连接失败:
{ "status": 502, "err": { "code": 502001, "msg": "后台数据库连接失败" }, "data": { } } |
如果正常:
{ "status": 200, "err": { "code": 0, "msg": "", }, "data": { 正常的返回数据 } |
支持分页、筛选、排序
REST API 背后的数据可能非常大,我们需要提效分页和筛选功能,以提高效率。
比如:/employees?lastName=Smith&age=30&page=2
或者:/aritcles?sort=+author, -datepublished 加号、减号代表排序顺序
加强安全
- 使用 TLS/SSL
- 贯彻最小特权原则 - 普通用户应该无法访问其他用户的信息,不能访问管理员的数据。不同角色的权限要有明确的控制。
使用缓存提高性能
使用缓存有助于提高性能,因为不用每次都查询数据库了。当然,缓存有可能过时,导致调试了生产时的一些问题。使用时要特别小心。
缓存的解决方案有 Redis, Memcache 等。
注意应在标头中使用 Cache-Control 来为使用者提供更详细的指引。
API 版本控制
API 接口改动可能会引起客户端的更改,为了提供更好的兼容性,我们应该提供版本控制。
常见的做法是在 API 路径开头提供 /v1 /v2 这样的前缀来表示API的版本。 /employees?lastName=Smith&age/employees?lastName=Smith&age=30