编写 Node.js Rest API 的 10 个最佳实践

Node.js 除了用来编写 WEB 应用之外,还可以用来编写 API 服务,我们在本文中会介绍编写 Node.js Rest API 的最佳实践,包括如何命名路由、进行认证和测试等话题,内容摘要如下:

  1. 正确使用 HTTP Method 和路由
  2. 正确的使用 HTTP 状态码
  3. 使用 HTTP Header 来发送元数据
  4. 为 REST API 挑选合适的框架
  5. 要对 API 进行黑盒测试
  6. 使用基于 JWT 的无状态的认证机制
  7. 学会使用条件请求机制
  8. 拥抱接口调用频率限制(Rate-Limiting)
  9. 编写良好的 API 文档
  10. 对 API 技术演化保持关注

 1. 正确使用 HTTP Method 和路由

  试想你正要构建一个 API 用来创建、更新、获取、删除用户,对于这些操作,HTTP 规范里面已经有了现成的操作:POST、PUT、GET、DELETE,建议直接使用他们来描述接口的行为。

  至于路由的命名,应该使用名词或名词性短语来作为资源标识符,比如上文提到的用户管理的例子,路由就应该长这样:

  • POST /users 或者 PUT /users/:id 用来创建新用户;
  • GET /users 用来获取用户列表;
  • GET /users/:id 用来获取单个用户;
  • PATCH /users/:id 用来更新用户信息;
  • DELETE /users/:id 用来删除用户;

 2. 正确的使用 HTTP 状态码

  如果服务器端在请求处理的过程中出错了,你必须设置正确的响应状态码,具体如下:

  • 2xx,表示一切正常;
  • 3xx,表示资源位置已经更改;
  • 4xx,表示因为客户端错误而导致请求无法被处理,比如参数校验没通过;
  • 5xx,表示因为服务器错误导致请求无法被处理,比如服务端抛了异常;

  如果你使用 express,设置状态码非常简单:res.status(500).send({ error: ‘Internal server error happend‘ }),如果使用了 restify,也是类似的:res.status(201)。

  如果想看完整的 HTTP 状态码,点击这里

 3. 使用 HTTP Header 来发送元数据

  如果想要发送关于响应体数据的元数据,可以使用 Header ,Header 可以包含的常见元数据包括如下几类:

  • 分页信息;
  • 频率限制信息;
  • 认证信息;

  如果你需要在 Header 中发送自定义的元数据,最好的做法是在 Header 名称前面加 X,例如,需要发送 CSRF Token 的时候,实际的 Header 应该命名为:X-CSRF-Token,然而,这种 Header 在?RFC 6648?中已经被废弃了。API 在设置自定义 Header 的时候还要尽可能避免命名冲突,比如为了达到这个目的OpenStack 为所有 API 的自定义 Header 都加上了 OpenStack 的前缀:


OpenStack-Identity-Account-ID
OpenStack-Networking-Host-Name
OpenStack-Object-Storage-Policy

  需要注意的是,虽然 HTTP 规范中没有规定 Header 的大小,但是 Node.js 中 Header 的大小被限制在了 80KB。官方原文如下:

不要让 HTTP Header ,包括其中状态码那行的整体大小超过 HTTP_MAX_Header_SIZE,这样做的目的是为了防御基于 Header 的 DDOS 攻击。点击这里

 4. 为 REST API 挑选合适的框架

  根据你的实际场景挑选合适的框架是非常重要的,Node.js 中的框架大致介绍如下:

  Express、Koa、HAPI

  ExpressKoaHAPI?主要是用来构建浏览器 WEB 应用,因为他们都支持服务端模板渲染,虽然这只是他们众多功能中的一个。如果你的应用需要提供用户界面,那么这三个就是不错的选择。

  Restify

  而?Restify?是专门用来创建符合 REST 规范的服务的,他诞生的目的就是帮你构建严格意义上的、可维护的 API 服务。Restify 内置了所有请求处理函数的?DTrace?支持。并且已经被?npm?和?netflix?用来在生产环境提供重要的服务。

 5. 要对 API 进行黑盒测试

  测试 API 的最好办法是对他们进行黑盒测试,黑盒测试是一种不关心应用内部结构和工作原理的测试方法,测试时系统任何部分都不应该被 mock。

  supertest?是可以用来对接口进行黑盒测试的模块之一,下面是基于测试框架?mocha?编写的一个测试用例,该用例的目的是检查接口是否能返回单条的用户数据:


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 的单元测试还是需要编写的。

 6. 使用基于 JWT 的无状态的认证机制

  因为 Rest API 必须是无状态的,因此认证机制也需要是无状态的,而基于 JWT(JSON Web Token) 的认证机制是无状态认证机制中的最佳解决方案。

  JWT 的认证机制包含三部分:

  1. Header:包含 token 的类型和哈希算法;
  2. payload:包含声明信息;
  3. 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 链接来访问。

 7. 学会使用条件请求机制

  条件请求机制是基于不同的 Header 表现出不同的行为的机制,可以认为这些 Header 就是请求处理方式的先决条件,如果条件满足,请求处理方式就会有所不同。

  可以利用这些 Header 检测服务器上的资源版本是否匹配特定的资源版本,这些 Header 的取值可以是如下的内容:

  • 资源的最后修改时间;
  • 资源的标签(随资源变化而变化);

  具体来说:

  • Last-Modified:标识资源的最新修改时间;
  • Etag:标识资源的标签;
  • If-Modified-Since:结合 Last-Modified Header 使用;
  • If-Non-Match:结合 Etag 使用;

  下面来看一个实际的例子:

  客户端不知道 doc 资源的任何版本,所以请求时即不能提供 If-Modified-Since,也不能提供 If-Non-Match 两个 Header,然后服务端在响应中会增加 Etag 和 Last-Modified 两个 Header。

  nodejs-resftul-api-with-conditional-request-without-previous-versions.png

  接下来,客户端再次请求相同的资源的时候,就可以带上 If-Modified-Since 和 If-Non-Match 这两个 Header 了,然后如果服务器端会检查资源是否修改,如果没有修改,直接返回 304 - Not Modified 状态码,而不重复发送资源的内容。

  nodejs-resftul-api-with-conditional-request-with-previous-versions.png

 8. 拥抱接口调用频率限制(Rate-Limiting)

  频率限制是用来控制调用方有对接口发起请求的次数,为了让你的 API 用户知道他们还剩下多少余额,可以设置下面的 Header:

  • X-Rate-Limit-Limit:特定时间段内允许的最多请求次数;
  • X-Rate-Limit-Remaining:特定时间段内剩余的请求次数;
  • X-Rate-Limit-Reset:什么时候请求频率限制次数会重置;

  大多数的 WEB 框架都支持上面这些 Header,如果内置不支持,也可以找到插件来支持,比如,如果你使用了 koa,可以使用?koa-rate-limit

  需要注意的是,不同的 API 服务提供商频率限制的时间窗差异会很大,比如 GitHub 是 60 分钟,而 Twitter 是 15 分钟。

 9. 编写良好的 API 文档

  编写 API 的目的当然是让别人使用并受益,提供良好的接口文档至关重要。下面这两个开源项目可以帮你创建 API 文档:

  如果你愿意使用第三方文档服务商,可以考虑?Apiary

 10. 对 API 技术演化保持关注

  过去几年中,API 技术方案领域出现了两种新的查询语言,分别是 Facebook 的 GraphQL 和 Netflix 的 Falcor,为什么需要他们呢?

  试想这种 API 接口请求:/org/1/space/2/docs/1/collaborators?include=email&page=1&limit=10,类似的情况会让 API 很快失控,如果你希望所有接口能返回类似的响应格式,那么 GraphQL 和 Falcor 就能帮你解决这个问题。

  关于 GraphQL

GraphQL 是一种用于 API 的查询语言,也是一种基于现有数据处理数据查询的运行时。GraphQL 为您的 API 中的数据提供了一个完整和可理解的描述,使用户能够准确地询问他们需要什么,使得随着时间推移的 API 演化更容易,GraphQL 还有强大的开发工具支持。 到这里阅读更多。

  关于 Falcor

Falcor 是支撑着 Netflix UI 的创新数据平台。Falcor 允许你将所有后端数据建模为 Node.js 服务商的单个虚拟 JSON 对象。在客户端可以使用熟悉的 JavaScript 操作、处理远程JSON对象。如果你知道你的数据,你就知道你的 API 长啥样。 到这里阅读更多。

 能带来灵感的优秀 API 设计

  如果你正在开发 Rest API 或者准备改进老版本的 API,这里收集了几个在线上提供服务、设计优秀并且非常直接借鉴的 API:

  希望读到这里的同学对如何用 Node.js 编写良好的 API 有更好的理解,如果有建议,欢迎评论中提出。
英文原文:https://blog.risingstack.com/10-best-practices-for-writing-node-js-rest-apis/

原文地址:https://www.cnblogs.com/lalalagq/p/9942910.html

时间: 2024-08-26 03:44:37

编写 Node.js Rest API 的 10 个最佳实践的相关文章

Java异常处理的10个最佳实践

本文作者: ImportNew - 挖坑的张师傅 未经许可,禁止转载! 异常处理在编写健壮的 Java 应用中扮演着非常重要的角色.异常处理并不是功能性需求,它需要优雅地处理任何错误情况,比如资源不可用.非法的输入.null 输入等等.Java 提供很多异常处理特性,通过内置的 try.catch.finally关键字实现.Java 同样允许创建新的异常和使用 throw 和 throws 抛出该异常.在实践中,异常处理不单单是知道语法这么简单.编写健壮的代码更像是一种艺术,而不是一门科学,在接

规模化敏捷开发的10个最佳实践(上)

[编者按]软件开发和採购人员常常会对现有软件开发方法.技巧和工具产生一些疑问.针对这些疑问,Kevin Fall 整理了五个软件方面的话题:Agile at Scale,Safety-Critical Systems.Monitoring Software-Intensive System Acquisition Programs,Managing Intellectual Property in the Acquisition of Software-Intensive Systems.以及

学画线框图:10个最佳实践

在设计过程的线框图绘制阶段,我们的思路很不成熟和粗糙.无论在废纸上.白板上或者用软件,绘制线框图有助于建立项目中各种元素之间的关系.这些元素譬如导航.图形.操作调用等.但是,如果我们将线框图当成一种工具,其使用目的就应当是:建立针对设计方案的用于协作沟通的创意空间,同时支持迭代和驱动快速思维. 那么如何才能使线框图成为有效驱动设计沟通呢? 评判的最佳方法是退一步,然后问一问这个问题:当我分享我的线框图时,沟通的内容与执行相关还是与我要创建的体验相关? 如果你的创造性头脑风暴和讨论被陷于"线框图看

网站优化建设的10个最佳实践

前天对于IT行业的人来说,做出几个网页不是件困难的事情.但这些网站并不意味着能够带来有效客户,帮助企业创造无限可能的收益. 网站的设计工作非常重要,因为访问者只需要0.05秒——即50毫秒就能够从主观上评判一个网站的好坏. 网站设计还会影响客户转化,企业信誉,并最终影响网站的成功. 从用户交互的角度来说:有关对网站的负面反馈中94%与设计有关,而38%的用户会放弃使用布局不吸引人的网站. 没有哪个网站是绝对完美,但深圳新龙的目标是使您的网站尽可能优化. 精心建设的网站将能够蓬勃发展起来,访问者更

使用node.js进行API自动化回归测试

概述 传统的QA自动化测试通常是基于GUI的,比如使用Selenium,模拟用户在界面上操作.但GUI测试的开发.维护成本和运行的稳定性一直是测试界的老大难问题.投入大量的人力物力开发.维护.运行,却得不到相应的回报,令许多同行头痛不已.不过端对端(end to end)测试确实是QA/测试团队的重点工作之一,是绕不过的坎,怎么破?今天就分享一下基于API(HTTP层面)的自动化测试,姑且叫它“半端对端 (semi end to end)”吧.其实我认为它已经接近95%端对端了,为什么这样说?

TypeScript + node.js + github.api, 实现github快速找到目标用户

一.TypeScript简介 1.定义 (1)Typescript = JavaScript + type + ( some other stuff ) (2)Typescript需要先被编译成Javascript,而后才能使用 2.demo 安装typescript: npm install typescript –g tsc index.ts index.ts: var fn = () => ‘response’ command line: tsc init 修改tsconfig.json的

使用Node.js完成的第一个项目的实践总结

http://blog.csdn.net/yanghua_kobe/article/details/17199417 项目简介 这是一个资产管理项目,主要的目的就是实现对资产的无纸化管理.通过为每个资产生成二维码,来联合移动终端完成对资产的审核等.这个项目既提供了Web端的管理界面也提供移动端(Andorid)的资产审核.派发等相关功能.我们用Node.js构建该项目的Web端以及移动端的Serveice API. 项目主框架:Express 简介 Express 是一个非常流行的Node.js

[转]10个有关RESTful API良好设计的最佳实践

Web API已经在最近几年变成重要的话题,一个干净的API设计对于后端系统是非常重要的. 通常我们为Web API使用RESTful设计,REST概念分离了API结构和逻辑资源,通过Http方法GET, DELETE, POST 和 PUT来操作资源. 下面是进行RESTful Web API十个最佳实践,能为你提供一个良好的API设计风格. 1.使用名词而不是动词 Resource资源 GET读 POST创建 PUT修改 DELETE /cars 返回 cars集合 创建新的资源 批量更新c

10个有关RESTful API良好设计的最佳实践

Web API已经在最近几年变成重要的话题,一个干净的API设计对于后端系统是非常重要的. 通常我们为Web API使用RESTful设计,REST概念分离了API结构和逻辑资源,通过Http方法GET, DELETE, POST 和 PUT来操作资源. 下面是进行RESTful Web API十个最佳实践,能为你提供一个良好的API设计风格. 1.使用名词而不是动词 Resource资源 GET读 POST创建 PUT修改 PATCH部分修改 DELETE /cars 返回 cars集合 创建