除了用来编写
- Node.js
应用之外,还可以用来编写
服务,我们在本文中会介绍编写
- API
的最佳实践,包括如何命名路由、进行认证和测试等话题,内容摘要如下:
- Node.js Rest API
和路由
- HTTP Method
状态码
- HTTP
来发送元数据
- HTTP Header
挑选合适的框架
- REST API
进行黑盒测试
- API
的无状态的认证机制
- JWT
文档
- API
技术演化保持关注
- API
试想你正要构建一个
用来创建、更新、获取、删除用户,对于这些操作,
- API
规范里面已经有了现成的操作:
- HTTP
、
- POST
、
- PUT
、
- GET
,建议直接使用他们来描述接口的行为。
- DELETE
至于路由的命名,应该使用名词或名词性短语来作为资源标识符,比如上文提到的用户管理的例子,路由就应该长这样:
或者
- POST /users
用来创建新用户;
- PUT /users/:id
用来获取用户列表;
- GET /users
用来获取单个用户;
- GET /users/:id
用来更新用户信息;
- PATCH /users/:id
用来删除用户;
- DELETE /users/:id
状态码
- HTTP
如果服务器端在请求处理的过程中出错了,你必须设置正确的响应状态码,具体如下:
,表示一切正常;
- 2xx
,表示资源位置已经更改;
- 3xx
,表示因为客户端错误而导致请求无法被处理,比如参数校验没通过;
- 4xx
,表示因为服务器错误导致请求无法被处理,比如服务端抛了异常;
- 5xx
如果你使用
,设置状态码非常简单:
- express
,如果使用了
- res.status(500).send({ error: 'Internal server error happend' })
,也是类似的:
- restify
。
- res.status(201)
如果想看完整的
状态码, 。
- HTTP
来发送元数据
- HTTP Header
如果想要发送关于响应体数据的元数据,可以使用
,
- Header
可以包含的常见元数据包括如下几类:
- Header
如果你需要在
中发送自定义的元数据,最好的做法是在
- Header
名称前面加
- Header
,例如,需要发送
- X
的时候,实际的
- CSRF Token
应该命名为:
- Header
,然而,这种
- X-CSRF-Token
在 中已经被废弃了。API 在设置自定义
- Header
的时候还要尽可能避免命名冲突,比如为了达到这个目的
- Header
为所有 API 的自定义
- OpenStack
都加上了
- Header
的前缀:
- OpenStack
- OpenStack-Identity-Account-ID
- OpenStack-Networking-Host-Name
- OpenStack-Object-Storage-Policy
不要让 HTTP
,包括其中状态码那行的整体大小超过 HTTP_MAX_Header_SIZE,这样做的目的是为了防御基于
- Header
的
- Header
攻击。
- DDOS
根据你的实际场景挑选合适的框架是非常重要的,
中的框架大致介绍如下:
- Node.js
、 、 主要是用来构建浏览器
应用,因为他们都支持服务端模板渲染,虽然这只是他们众多功能中的一个。如果你的应用需要提供用户界面,那么这三个就是不错的选择。
- WEB
而 是专门用来创建符合
规范的服务的,他诞生的目的就是帮你构建严格意义上的、可维护的
- REST
服务。
- API
内置了所有请求处理函数的 支持。并且已经被 和 用来在生产环境提供重要的服务。
- Restify
测试
的最好办法是对他们进行黑盒测试,黑盒测试是一种不关心应用内部结构和工作原理的测试方法,测试时系统任何部分都不应该被
- API
。
- mock
是可以用来对接口进行黑盒测试的模块之一,下面是基于测试框架 编写的一个测试用例,该用例的目的是检查接口是否能返回单条的用户数据:
- const request = require('supertest')
- describe('GET /user/:id', function() {
- it('returns a user', function() {
- // newer mocha versions accepts promises as well
- return request(app)
- .get('/user')
- .set('Accept', 'application/json')
- .expect(200, {
- id: '1',
- name: 'John Math'
- }, done);
- });
- });
可能有人会问:
服务所连接的数据库里面的数据是如何写进去的呢?
- API
通常来说,你写测试的时候,要尽可能不对系统状态做假设,然而在某些场景下,你需要准确的知道系统当前所处的状态以增加更多的断言来提高测试覆盖率。如果你有这种需求,你可以试用如下的方法对数据库进行预填充:
此外,有了黑盒测试并不意味着不需要单元测试,针对
的 还是需要编写的。
- API
因为
必须是无状态的,因此认证机制也需要是无状态的,而基于
- Rest API
的认证机制是无状态认证机制中的最佳解决方案。
- JWT(JSON Web Token)
的认证机制包含三部分:
- JWT
:包含
- Header
的类型和哈希算法;
- token
:包含声明信息;
- payload
:
- signature
实际上并不是对
- JWT
进行加密,只是对其做了签名;
- payload
为
添加基于
- API
的认证机制也非常的简单,比如下面的代码:
- JWT
- const koa = require('koa');
- const jwt = require('koa-jwt');
- const app = koa();
- app.use(jwt(secret: 'very-secret'
- }));
- // Protected middleware
- app.use(function * ()
- // content of the token will be available on this.state.user
- this.body = {
- secret: '42'
- }
- });
有了如上的代码,你的
就有了
- API
的保护。如果要访问这种被保护的接口,需要使用
- JWT
来提供
- Authorization Header
,比如:
- token
- curl --Header "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ" my-website.com
你可能注意到了,
模块并不依赖任何数据存储层,这是因为
- JWT
本身是可以单独被校验的,
- token
里面的
- token
甚至可以包含
- payload
的签名时间、有效期限。
- token
此外,你还需要确保,所有的
接口只能通过更安全的
- API
链接来访问。
- HTTPS
条件请求机制是基于不同的
表现出不同的行为的机制,可以认为这些
- Header
就是请求处理方式的先决条件,如果条件满足,请求处理方式就会有所不同。
- Header
可以利用这些
检测服务器上的资源版本是否匹配特定的资源版本,这些
- Header
的取值可以是如下的内容:
- Header
具体来说:
:标识资源的最新修改时间;
- Last-Modified
:结合
- If-Modified-Since
使用;
- Last-Modified Header
:结合
- If-Non-Match
使用;
- Etag
下面来看一个实际的例子:
客户端不知道
资源的任何版本,所以请求时即不能提供
- doc
,也不能提供
- If-Modified-Since
两个 Header,然后服务端在响应中会增加
- If-Non-Match
和
- Etag
两个
- Last-Modified
。
- Header
接下来,客户端再次请求相同的资源的时候,就可以带上
和
- If-Modified-Since
这两个
- If-Non-Match
了,然后如果服务器端会检查资源是否修改,如果没有修改,直接返回
- Header
状态码,而不重复发送资源的内容。
- 304 - Not Modified
频率限制是用来控制调用方有对接口发起请求的次数,为了让你的
用户知道他们还剩下多少余额,可以设置下面的
- API
:
- Header
大多数的
框架都支持上面这些
- WEB
,如果内置不支持,也可以找到插件来支持,比如,如果你使用了
- Header
,可以使用 。
- koa
需要注意的是,不同的
服务提供商频率限制的时间窗差异会很大,比如
- API
是 60 分钟,而
- GitHub
是 15 分钟。
编写
的目的当然是让别人使用并受益,提供良好的接口文档至关重要。下面这两个开源项目可以帮你创建
- API
文档:
- API
如果你愿意使用第三方文档服务商,可以考虑 。
过去几年中,
技术方案领域出现了两种新的查询语言,分别是
- API
的
和
- GraphQL
的
- Netflix
,为什么需要他们呢?
- Falcor
试想这种 API 接口请求:
,类似的情况会让 API 很快失控,如果你希望所有接口能返回类似的响应格式,那么
- /org/1/space/2/docs/1/collaborators?include=email&page=1&limit=10
和
- GraphQL
就能帮你解决这个问题。
- Falcor
GraphQL 是一种用于 API 的查询语言,也是一种基于现有数据处理数据查询的运行时。GraphQL 为您的 API 中的数据提供了一个完整和可理解的描述,使用户能够准确地询问他们需要什么,使得随着时间推移的 API 演化更容易,GraphQL 还有强大的开发工具支持。 到 阅读更多。
Falcor 是支撑着 Netflix UI 的创新数据平台。Falcor 允许你将所有后端数据建模为 Node.js 服务商的单个虚拟 JSON 对象。在客户端可以使用熟悉的 JavaScript 操作、处理远程 JSON 对象。如果你知道你的数据,你就知道你的 API 长啥样。 到 阅读更多。
如果你正在开发
或者准备改进老版本的
- Rest API
,这里收集了几个在线上提供服务、设计优秀并且非常直接借鉴的
- API
:
- API
希望读到这里的同学对如何用
编写良好的
- Node.js
有更好的理解,如果有建议,欢迎评论中提出。
- API
来源: http://www.tuicool.com/articles/rE3ii2Z