Skip to main content

使用 TypeScript 构建 Koa2 RESTful API 最佳的脚手架

· 9 min read
Zeffon Wu

koa2 是基于 NodeJS 下一代 Web 开发框架。但是,Koa2 并没法像 Java 的 SpringBoot 框架那般开箱即用。Koa2 如果不通过二次封装,真的很难直接作为 Web 开发框架开发具体的业务。 Koa 最主要的核心就是 应用上下文 和 中间件。因此,Koa2 如果想要像 SpringBoot 可以给开发者开箱即用,显然是不可能。而且,Koa2 在以前版本是不支持 ESModule 的,即无法使用 import 导入,只能使用 require。不过目前 Koa 依赖 node v7.6.0+ 或 ES2015 及更高版本和 async 方法支持,可以实现 ESModule 方式的使用。 随着 Typescript 的普及,作为 NodeJS 的开发框架当然使用 TS 类型才能降低维护成本。对此,本人在 Koa2 + Typescript 的基础集成了一个 Web 开发框架 -- koa-web大家要是觉得koa-web不错,可以给个star谢谢!

前言

koa2 是基于 NodeJS 下一代 Web 开发框架。但是,Koa2 并没法像 Java 的 SpringBoot 框架那般开箱即用。Koa2 如果不通过二次封装,真的很难直接作为 Web 开发框架开发具体的业务。 Koa 最主要的核心就是 应用上下文 和 中间件。因此,Koa2 如果想要像 SpringBoot 可以给开发者开箱即用,显然是不可能。而且,Koa2 在以前版本是不支持 ESModule 的,即无法使用 import 导入,只能使用 require。不过目前 Koa 依赖 node v7.6.0+ 或 ES2015 及更高版本和 async 方法支持。 随着 Typescript 的普及,作为 NodeJS 的开发框架当然使用 TS 类型才能降低维护成本。对此,本人在 Koa2 + Typescript 的基础集成了一个 Web 开发框架 -- koa-web大家要是觉得koa-web不错,可以给个star谢谢!

koa-web Github 地址:https://github.com/zeffon/koa-web

koa-web npm 地址:https://www.npmjs.com/package/create-koa-web

正文

Koa-web

  • 💡 TypeScript: 支持 TypeScript
  • 🎨 prettier:prettier 规范代码格式
  • 🚀 全局异常:全局异常统一处理
  • ✈️ 数据校验:实用且高效的数据校验方式
  • 🍀 Database:支持 Sequelize 连接
  • 🔥 Redis:支持 Redis 数据库连接
  • Cache:支持 本地缓存
  • ✍️ Auth:通用 JWT 授权
  • 📖 日志:记录 SQL 日志和错误日志
  • 单元测试:支持单元测试
  • 📝 API 文档:API 文档测试

运行

如果你想要使用 koa-web 来作为 web 开发框架,是不需要下载 github 代码,直接使用 npm 命令快速搭建脚手架

$ npm create koa-web@latest
# 或者指定项目名称
$ npm create koa-web@latest koa-web-project

安装完毕,即可运行

# 1. 打开安装的项目
$ cd koa-web-project

# 2. 安装依赖
$ npm install

# 3. 运行项目
$ npm run start

# 4. 打开在线文档
# please open in: http://127.0.0.1:3000/koa-web/v1/doc.html

使用

一个 web 开发框架最核心、最基础的无非就是从异常处理和数据校验这两个模块开始。

全局异常

借助 Koa2 中间件的特性实现了全局异常捕获及处理。 Koa-web 中,异常分为两种:

  1. 已知异常
  2. 未知异常

已知异常(HTTP 异常) 又分为:

  1. 参数异常 ParameterException
  2. 未授权异常 UnAuthenticatedException
  3. 禁止访问异常 ForbiddenException
  4. 404 异常 NotFoundException
  5. 服务不可用异常 ServerErrorException
  6. 数据操作 GET、POST、PUT、DELETE(Koa-web 对数据操作成功也算是一种异常)

通过在 exception-code定义相对应错误码错误提示,抛出去异常就可以统一格式了。 在系统初始化阶段,UnifyResponse统一返回格式 赋值给 global.UnifyResponse,之后在编写业务代码便可以使用 global.UnifyResponse根据确定的异常分类返回对应的异常信息。

未知异常 一般是未发现的异常提示,目前可以通过记录日志的方式记录该异常信息。

数据校验

数据校验有两种校验层次,一种是基于 koa-swagger-decorator 进行简单参数传递的校验,另一种是基于 validator 封装的复杂参数校验 LinValidator(来自 7 七月老师)。 koa-swagger-decorator 中的参数校验也是基于 validator 上。而 Koa-web 为什么有了 自己封装的参数校验器,还要使用 koa-swagger-decorator 呢?使用 koa-swagger-decorator 是想让 Koa-web 可以 在线 API 文档 调试,而 koa-swagger-decorator 在参数传递上有自己一套校验规则,权衡一二后,将简单规则的校验放在 koa-swagger-decorator ,而 LinValidator 用来校验复杂参数。

  1. koa-swagger-decorator 的详细规则使用可以查看其官方 Github 地址
  2. LinValidator 的使用

Koa-web 相关模块的校验器是统一放置在 src/app/api/valid 目录下,比如:

export class RegisterValidator extends LinValidator {
private email;
private nickname;
private password1;
private password2;
private remark;

constructor() {
super();
this.email = [
new Rule("isLength", "Min 12 characters, max 32 characters", {
min: 6,
max: 32,
}),
new Rule("isEmail", "Please enter email format"),
];
this.nickname = [
new Rule("isLength", "Nickname does not match the length", {
min: 4,
max: 32,
}),
];
this.password1 = [
new Rule("isLength", "Password has min 6 characters, max 32 characters", {
min: 6,
max: 32,
}),
new Rule(
"matches",
"Password does not meet specifications",
"^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]"
),
];
this.password2 = this.password1;
this.remark = [
new Rule("isOptional"), // 可选,不校验
];
}

validatePassword(vals: any) {
const password1 = vals.body.password1;
const password2 = vals.body.password2;
if (password1 !== password2) {
throw new Error("Both passwords must be the same");
}
}
}

Auth 认证

core 目录下 auth 模块是认证机制。Koa-web 的授权机制是基于 jsonwebtoken颁发校验 Token 令牌的。Koa-web 全局拦截所有请求,除了在 unlessPaths 中路由,其它所有的请求都需要在请求头上携带 authorization 参数后才能正常访问,不然只能返回 401 请求。 unlessPaths 中路由数组就是过滤 url 路由。unlessPaths 支持字符串精准的路由和正则匹配规则的路由方式(推荐使用正则方式)。

let unlessPaths = [
/^\/koa-web\/v1\/json\.html[\/#\?]?$/i,
/^\/koa-web\/v1\/doc\.html[\/#\?]?$/i,
/^\/koa-web\/v1\/user\/login[\/#\?]?$/i,
/^\/koa-web\/v1\/user\/register[\/#\?]?$/i
]
# 或者
let unlessPaths = [
'/koa-web/v1/json.html',
'/koa-web/v1/doc.html',
'/koa-web/v1/user/login',
'/koa-web/v1/user/register'
]

数据库连接

数据库是 sequelize 进行连接的,采用 MySQL 引擎。而对数据库操作采用 sequelize模型。可以参考 Koa-web 中的 user 模块进行模型设计,配置上正确的数据库地址便可以生成对应的表结构。配置文件在 config 目录下,分有三种运行环境文件,选择当前运行环境的文件进行配置 DATABASE 相关参数配置。

src/app/api/model 下编写对应的模型,并且需要在 index.ts 进行导出,会在 src/core/database/init.ts 检测到定义的模型,进行数据库表创建。

Redis 数据库

config 配置下,REDIS.ENABLED 是否开启 Redis 服务,填写正确的 redis 的 host、port、password 连接 Redis 客户端。提供三个方法操作数据的存储、获取、删除,更多方法可以进行扩展。

本地缓存

本地缓存是存储在 NodeJS 进程中,会随着进程的重启而被清楚缓存数据。可以存储一些不重要的数据。

API 文档

API 文档 是采用 koa-swagger-decorator 实现的。可以通过装饰器的方式,更加简洁将 api 接口编码出来。并且借助 koa-swagger-decorator 实现简单的参数校验。在 API 文档上可以更加方便地、直观地进行调试接口。