Nest
官网:https://nestjs.com/
中文网站:https://docs.nestjs.cn/
评价: https://mp.weixin.qq.com/s/Y67O9ks-qPwVF8UqHaRY-g
Nest 是一个渐进的 Node.js 框架,可以在 TypeScript 和 JavaScript (ES6、ES7、ES8)之上构建高效、可伸缩的企业级服务器端应用程序。
Nest 基于 TypeScript 编写并且结合了 OOP(面向对象编程),FP(函数式编程)和 FRP (函数式响应编程)的相关理念。在设计上的很多灵感来自于 Angular,Angular 的很多模式又来自于 Java 中的 Spring 框架,依赖注入、面向切面编程等,所以我们也可以认为:Nest 是 Node.js 版的 Spring 框架。
Nest 框架底层 HTTP 平台默认是基于 Express 实现的,所以无需担心第三方库的缺失。
Nest 旨在成为一个与平台无关的框架。 通过平台,可以创建可重用的逻辑部件,开发人员可以利用这些部件来跨越多种不同类型的应用程序。
从技术上讲,Nest 可以在创建适配器后使用任何 Node HTTP 框架。有两个支持开箱即用的 HTTP 平台:express 和 fastify。您可以选择最适合您需求的产品。
NestJs 的核心思想:就是提供了一个层与层直接的耦合度极小,抽象化极高的一个架构体系。
建立项目
//安装Nest CLI
npm i -g @nestjs/cli .
//使用Nest CLI 创建项目
nest new project-name
// 运行项目
npm run start
src目录核心文件
app.controller.ts | 带有单个路由的基本控制器示例。 |
---|---|
app.module.ts | 应用程序的根模块。 |
main.ts | 应用程序入口文件。它使用 NestFactory 用来创建 Nest 应用实例。 |
NEST命令行工具
nest --help
可以列出命令行的主要命令以及帮助
创建
- new(简写n)[options] [name] :创建一个NEST应用,例如 nest n hello-world。选项中支持:
- --directory 指定目标目录
- -d或--dry-run 不输出创建过程中的报告
- -g或--skip-git 不要初始化git仓库(默认是会在项目创建git仓库)
- -s或--skip-install 不要安装依赖哭
- -p或--package-manager [name] 指定包管理工具
- -l或--language [lang] 指定语言JS或者TS
- -c或--collection [name] 用特定的架构生成项目
构建
- build [options] [app] : 构建项目,默认会将TS文件构建到项目的dist目录中;options有:
- -c或--config [path] 用cli构建时特定的配置文件
- -p或--path [path] tsconfig配置文件
- -w或--watch 实时重加载,观察模式
- --watchAssets 观察非ts文件模式
- --webpackPath [path] webpack的配置文件
- --tsc 使用tsc编译
运行
- start [options] [app]:运行NEST项目,options有:
- -c或--config [path] 用cli构建时特定的配置文件
- -p或--path [path] tsconfig配置文件
- -w或--watch 实时重加载,观察模式
- --watchAssets 观察非ts文件模式
- -d或--debug [hostport] 调试模式
- --webpack用webpack编译
- --webpackPath [path] webpack的配置文件
- --tsc 使用tsc编译
- -e或--exec [binary] 以二进制运行(默认用node)
- --preserveWatchOutput tsc的观察模式
更新
- update或u [options]:更新当前项目的依赖组件
- -f或--force 强制重新安装依赖
- -t或--tag 升级被打上(latest | beta | rc | next tag)的组件
Nest架构元素
其类型如下表:
名称 | 别名 | 说明 |
---|---|---|
application | application | 在工作区中创建一个新的应用 |
class | cl | 新的类 |
configuration | config | 命令行的配置文件 |
controller | co | 控制器 |
decorator | d | 自定义装饰器 |
filter | f | 过滤器 |
gateway | ga | 请求的网关 |
guard | gu | 守卫 |
interceptor | in | 拦截器 |
interface | interface | 接口 |
middleware | mi | 中间件 |
module | mo | 模块 |
pipe | pi | 管道 |
provider | pr | 功能组 |
resolver | r | GraphQL处理器 |
service | s | 服务 |
library | lib | 单独库模式下创建一个库 |
sub-app | app | 子应用 |
resource | res | 一个数据模型的CRUD |
平台
Nest 旨在成为一个与平台无关的框架。 通过平台,可以创建可重用的逻辑部件,开发人员可以利用这些部件来跨越多种不同类型的应用程序
有两个支持开箱即用的 HTTP 平台:express 和 fastify
暴露自己的 API分别是 NestExpressApplication 和 NestFastifyApplication
const app = await NestFactory.create<NestExpressApplication>(AppModule);
控制器
控制器负责处理传入的 请求 和向客户端返回 响应
创建一个基本的控制器:类和装饰器
CLI 创建控制器
$ nest g controller cats
路由
Nestjs 中没有单独配置路由的地方。定义好控制器后 nestjs 会自动给我们配置对应的路由
//中控制器内直接用装饰器匹配路由
@Get()
index() {
//输出内容
return '我是article控制器get请求';
}
两种不同的操作响应:** 标准(推荐)和 类库**
关于 nest 的 return: 当请求处理程序返回 JavaScript 对象或数组时,它将自动序列化为JSON。但是,当它返回一个字符串时,Nest 将只发送一个字符串而不是序列化它。这使响应处理变得简单:只需要返回值,Nest 负责其余部分。
类库响应方式
通过 @Res() 注入类库特定的 响应对象
import { Controller, Get, Post, Res, HttpStatus } from '@nestjs/common';
import { Response } from 'express';
@Controller('cats')
export class CatsController {
@Post()
create(@Res() res: Response) {
res.status(HttpStatus.CREATED).send();
}
@Get()
findAll(@Res() res: Response) {
res.status(HttpStatus.OK).json([]);
}
}
类库方式失去了与依赖于 Nest 标准响应处理的 Nest 功能的兼容性,例如拦截器和 @HttpCode() 装饰器。此外,您的代码可能变得依赖于平台(因为底层库可能在响应对象上有不同的 API),并且更难测试(您必须模拟响应对象等)。因此,在可能的情况下,应始终首选 Nest 标准方法
装饰器
装饰器将类与所需的元数据相关联,并使 Nest 能够创建路由映射
请求装饰器
Nestjs也提供了其他HTTP请求方法的装饰器 @Put() 、@Delete()、@Patch()、 @Options()、 @Head()和 @All()
用法都差不多
import { Controller, Get } from '@nestjs/common';
@Controller('cats')
export class CatsController {
@Get()
findAll(): string {
return 'This action returns all cats';
}
}
获取Get 传值或者Post 提交的数据
@Request() | req |
---|---|
@Response() | res |
@Next() | next |
@Session() | req.session |
@Param(key?: string) | req.params / req.params[key] |
@Body(key?: string) | req.body / req.body[key] |
@Query(key?: string) | req.query / req.query[key] |
@Headers(name?: string) | req.headers / req.headers[name] |
import {Body, Controller, Get, Post, Query, Request} from '@nestjs/common';
@Controller('article')
export class ArticleController {
//get请求
@Get()
index() {
//输出内容
return '我是article控制器';
}
//路由拼接article/add
@Get('add')
//获取url装饰器(get参数)
addArticle(@Query() query) {
console.log(query)
//输出内容
return '我是article/add';
}
@Get('edit')
//request装饰器获取请求信息
editArticle(@Request() req){
console.log(req.query)
return "我是article/edit"
}
@Post('create')
//Body装饰器获取post内容
create(@Body() body){
console.log(body)
return '我是Post请求'
}
}
状态码
@HttpCode
@Post()
@HttpCode(204)
create() {
return 'This action adds a new cat';
}
重定向
@Redirect()
@Get()
@Redirect('https://nestjs.com', 301)
子域路由
@Controller 装饰器可以接受一个 host 选项,以要求传入请求的 HTTP 主机匹配某个特定值
@Controller({ host: 'admin.example.com' })
export class AdminController {
@Get()
index(): string {
return 'Admin page';
}
}
动态路由
不常用
注意动态路由要放在下面,不然会先匹配,下面路由匹配不成功
import {Controller, Get, Param, Query} from '@nestjs/common';
@Controller('news')
export class NewsController {
@Get()
addDate(@Query('id') id){
console.log(id)
return "获取里面参数"
}
//news/123
@Get(":id")
index(@Param() param){
//{id: '123'}
console.log(param)
return "我是动态路由"
}
}
请求负载
使用 TypeScript, POST接受客户端参数,需要确定 DTO(数据传输对象)模式
DTO是一个对象,它定义了如何通过网络发送数据,通过使用 TypeScript接口或简单的类实现(推荐使用类)
区别:类是JavaScript ES6标准的一部分,因此它们在编译后的 JavaScript中保留为实际实体。另一方面,由于 TypeScript接口在转换过程中被删除
创建 CreateCatDto 类
create-cat.dto.ts
export class CreateCatDto {
readonly name: string;
readonly age: number;
readonly breed: string;
}
它只有三个基本属性。 之后,我们可以在 CatsController中使用新创建的DTO
cats.controller.ts
@Post()
async create(@Body() createCatDto: CreateCatDto) {
return 'This action adds a new cat';
}
完整示例
import { Controller, Get, Query, Post, Body, Put, Param, Delete } from '@nestjs/common';
import { CreateCatDto, UpdateCatDto, ListAllEntities } from './dto';
@Controller('cats')
export class CatsController {
@Post()
create(@Body() createCatDto: CreateCatDto) {
return 'This action adds a new cat';
}
@Get()
findAll(@Query() query: ListAllEntities) {
return `This action returns all cats (limit: ${query.limit} items)`;
}
@Get(':id')
findOne(@Param('id') id: string) {
return `This action returns a #${id} cat`;
}
@Put(':id')
update(@Param('id') id: string, @Body() updateCatDto: UpdateCatDto) {
return `This action updates a #${id} cat`;
}
@Delete(':id')
remove(@Param('id') id: string) {
return `This action removes a #${id} cat`;
}
}
最后一步
控制器已经准备就绪,但是 Nest 不知道 CatsController 是否存在
app.module.ts
import { Module } from '@nestjs/common';
import { CatsController } from './cats/cats.controller';
@Module({
controllers: [CatsController],
})
export class AppModule {}
使用 @Module()装饰器将元数据附加到模块类,Nest 现在可以轻松反映必须安装的控制器
配置静态资源
nest若要加载静态资源则需要配置静态资源目录
入口文件src/main
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
//入口文件引入express平台HTTP平台
import { NestExpressApplication } from '@nestjs/platform-express'
//引入path模块的join方法
import {join} from "path";
async function bootstrap() {
const app = await NestFactory.create<NestExpressApplication>(AppModule);
// app.useStaticAssets('public'); //配置静态资源目录
app.useStaticAssets(join(__dirname, '..', 'public'), { //配置虚拟目录
prefix: '/static/', //设置虚拟路径
});
await app.listen(3000);
}
bootstrap();