Nest + TypeScript + TypeOrm + JWT
序: 个人觉得 JavaScript 最大优势是灵活,最大的缺点也是灵活。开发速度快,但是调试和维护花费的时间会比强类型语言花的时间多很多,运行时报错,是我觉得它作为后端语言很大的一个问题,开发时跨文件调用 IDE 的函数以及变量提示,以及类型的限定也是我觉得JS的一些开发问题。这些问题在Typescript得到了很好的解决,加上面向对象的东西能在TS上实现,其实基础的东西在node上都能做了。
由于公司目前的技术栈是js, 后端在node.js 中用的比较多的服务端开发框架是,egg、nest、 koa、express等。
在之前的项目中,公司是采用的是egg,也研究了一些上ts的方式。但是由于项目之前存在比较多的问题,准备重构之前的代码。对,我就是在坚定的推动TS的那个人。
egg 对ts的支持不是很好,对于TS的支持,阿里在egg的基础上有 midway,个人写了下demo感觉不是很那啥,可能还在开发中吧,喜欢的朋友可以支持下哦。所以我放弃了原先的egg。
在node 中选择TS的框架,选择了Nest.js,下面列举nest我认为比较好一点。
Nest的优势:
- Nest 类似于java中的 Spring Boot ,吸取了很多优秀的思想和想法,有想学习spring boot的前端同学,可以从这个搞起。对于这种后端过来的全栈比较容易就能上手。
- egg star(目前为止) : 15.7K,而 nest 有28.1k
- egg 有的, nest 基本上都有。
- Nest 面对切面,对面对对象和面向切面支持的非常好。
- 依赖注入容器(midway也是这种形式)
Nest的劣势:
- 国内用的人不多,但是我发现国内也有很多人在搞。
好了废话,不多说,上教学地址:github.com/liangwei010…
生命周期
- 当客户端一个Http请求到来时,首先过的中间件。
- 再是过的守卫(守卫只有通过和不通过)。
- 拦截器(这里我们可以看到,我们在执行函数前后都能做某些事情,统一的返回格式等等)。
- 管道,我们可以做参数校验和值的转换。
- 最后才会到Controller,然后就返回给客户端数据。
这里是我的项目的目录结构,大家也可以不按这个来。同层级的只列出部分,详细请看代码。
1 | scss复制代码project |
Controller 层
Controller 和常规的spring boot的 Controller 或者egg之类的是一样的。就是接收前端的请求层。**建议:**业务不要放在 Controller 层,可以放在service层。如果service文件过大,可以采用namespace的方式进行文件拆分。
1 | less复制代码@Controller() // 这里是说明这是一个Controller层 |
Service 层
Service 层我这边是做的是一些业务的处理层,所以Controller 层的默认的.spec.ts测试文件,我是删掉的,因为,我的单元测试是在xx.service.spec.ts 中。
1 | ini复制代码@Injectable() |
Service 单元测试
- 单元测试分两种,一种是连接数据库的测试,一种是mock数据,测试逻辑是否正确的测试。这里先展示mock的。
1 | scss复制代码const user = { |
这里有一个国外大佬写的测试,还蛮全的,有需要的可以看看:github.com/Zhao-Null/n…
DTO (数据库传输对象)
这个也不是java里面的独有的名词,DTO是数据库传输对象,所以,在我们前端传输数据过来的时候,我们需要校验和转换成数据库表对应的值,然后去save。
这里讲解下nest的DTO,在Controller处理前,我们需要校验参数是否正确,比如,我们需要某个参数,而前端没有传递,或者传递类型不对。
1 | typescript复制代码// 设置全局验证管道 |
1 | less复制代码// 创建用户dto |
1 | less复制代码// Controller 中 使用dto(当然要记得注册先,稍后讲解全局注册) |
例如 account字段 在前端传递的参数为空时,或者类型不对时,将会返回 [ “account is null”, “account is to require” ],这些个错误。这种防止到业务层做过多的判断,减少很多事情。当然,这里也是支持转化的,比如 字符串 “1” 转成数字 1,这种的,详情请看链接:docs.nestjs.com/pipes
全局超时时间
设置全局的超时时间,当请求超过某个设定时间时,将会返回超时。
1 | arduino复制代码 //main.ts |
1 | arduino复制代码/** |
全局成功返回格式
统一返回的格式,方便统一处理数据和错误。
1 | kotlin复制代码import { Injectable, NestInterceptor, CallHandler, ExecutionContext } from '@nestjs/common'; |
全局成功异常的格式
这里分自定义异常和其它异常,自定义将会返回自定义异常的状态码和系统。而其它异常将会返回异常和,系统返回的错误。
1 | typescript复制代码import { ArgumentsHost, Catch, ExceptionFilter, HttpException, HttpStatus } from '@nestjs/common'; |
JWT的封装
官网的jwt的例子,在每个函数如果需要接口校验都需要加 @UseGuards(AuthGuard()) 相关的注解,但是大部分接口都是需要接口验证的。所以这里我选择了自己封装一个。
这里我有写2种方式,如果有适合自己的,请选择。
- 方式1:自己封装一个注解。
这里是我们重写的本地校验类的名称,继承于AuthGuard
1 | scala复制代码///auth.local.guard.ts |
这里是我们的JWT校验类的名称,继承于AuthGuard
1 | scala复制代码///jwt.auth.guard.ts |
1 | scala复制代码/// jwt.strategy.ts |
这里抛出了一个自定义异常,在上面有写的。
1 | typescript复制代码/// local.strategy.ts |
全局守卫,这里的核心就是,当我们去执行时,看有没有 no-auth 的注解,有的话,就直接跳过,不走默认的jwt和自定义(登录)校验。当然,我们也是在这里写相关的白名单哦。先看注解吧。
1 | typescript复制代码import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common'; |
有 @NoAuth()的将不在进行任何校验,其他接口默认走JwtAuthGuard和 LocalAuthGuard校验
1 | arduino复制代码// 自定义装饰器 |
1 | less复制代码/// user.controller.ts |
- 方式2:就是在配置里头添加一个白名单列表,然后在守卫处判断。这个代码就不写了吧,不复杂的,随便搞搞就有了。
到这里基本的resetful接口和业务逻辑就能跑起来了,下节课讲解队列,graphql,等相关业务开发经常用到的东西,下次再见。
本文转载自: 掘金