阅读 179

Nestjs成长足迹(一):Nest介绍、swagger的使用

前言

本文章记录自己学习Nest的过程,适于前端及对后端没有基础但对Nest感兴趣的同学,如有错误,欢迎各位大佬指正

Nestjs介绍

Nest 是一个用于构建高效,可扩展的 Node.js 服务器端应用程序的框架。它使用渐进式 JavaScript,内置并完全支持 TypeScript(但仍然允许开发人员使用纯 JavaScript 编写代码)并结合了 OOP(面向对象编程),FP(函数式编程)和 FRP(函数式响应编程)的元素。

在底层,Nest使用强大的 HTTP Server 框架,如 Express(默认)和 Fastify。Nest 在这些框架之上提供了一定程度的抽象,同时也将其 API 直接暴露给开发人员。这样可以轻松使用每个平台的无数第三方模块。

Nest安装构建项目

// 先全局安装nest脚手架 npm install -g @nestjs/cli // 创建项目 nest new xxx 复制代码

image.png

  • 在这我选择更为熟悉且速度更快的yarn

  • 如下图是项目构建完后打开的目录结构

image.png

Nest的快捷命令

  • nest g mo kylin 创建一个kylin模块,文件目录不写,默认创建和文件名一样的kylin目录,在kylin目录下创建一个kylin.module.ts

//语法 nest g [文件类型] [文件名] [文件目录] nest g mo nest g co nest g service nest g res user 复制代码

  • 注意创建顺序: 先创建Module, 再创建ControllerService, 这样创建出来的文件在Module中自动注册,反之,后创建Module, ControllerService,会被注册到外层的app.module.ts

  • 如果忘记命令可以使用nest --help进行查看 nest --help

image.png

  • 示例:nest g res user

image.png

  • 在此我选择REST API风格的

  • nest g res user就是创建完整的user模块,这个命令执行完后会生成一个user文件夹,在这个文件夹中包含如下图所示的文件

    • dto用于定义系统内的接口或者输入和输出

    • entitiesmysql数据库中的一张表的实体文件,但要在文件中使用@Entity装饰器,这个在下文中介绍数据库连接、增删改查时会使用到

    • 这个后缀为spec的文件是测试文件,在快速开发的情况下,比较少用到这个文件,如果不需要每次都生成这个文件,可以在nest-cli.json文件中添加如下配置,禁用测试用例生成

"generateOptions": { "spec": false } 复制代码

image.png

文件解释
app.controller.spec.ts对于基本控制器的单元测试样例
app.controller.ts带有单个路由的基本控制器示例。
app.module.ts应用程序的根模块。
app.service.ts带有单个方法的基本服务。
main.ts应用程序入口文件。它使用 NestFactory 用来创建 Nest 应用实例。

image.png

运行Nest

  • 看到package.json文件

    • yarn start:运行项目(未启用热更新)

    • yarn start:dev:运行项目(启用热更新) image.png

  • 一般运行项目都会启用热更新,所以我将yarn startyarn start:dev进行合并,简洁点使用yarn start

image.png

  • 运行项目后,访问本地3000端口即可看见经典的hello world

image.png

  • hello world是如何显示出来的呢, 让我们看看它的结构

// app.controller.ts import { Controller, Get } from '@nestjs/common'; import { AppService } from './app.service'; @Controller() export class AppController {   constructor(private readonly appService: AppService) {}   @Get()   getHello(): string {     return this.appService.getHello();   } } 复制代码

// app.service.ts import { Injectable } from '@nestjs/common'; @Injectable() export class AppService {   getHello(): string {     return 'Hello World!';   } } 复制代码

  • app.controller.ts文件中引入了app.service.ts中的AppSerice类,在这个类中有一个getHello的方法返回了hello world

  • 而在app.controller.ts中使用@Get装饰器装饰了getHello方法,表示这是一个get请求

  • 仅有app.controller.tsapp.controller.ts是不够的,还有app.module.ts,在这个文件中引入了app.controller.tsapp.controller.ts,而在main.ts中引入了app.module.ts

// app.module.ts import { Module } from '@nestjs/common'; import { AppController } from './app.controller'; import { AppService } from './app.service'; import { UserModule } from './user/user.module'; @Module({   imports: [UserModule],   controllers: [AppController],   providers: [AppService], }) export class AppModule {} 复制代码

  • module中的模块介绍如下

    模块介绍
    imports导入模块的列表,这些模块导出了此模块中所需提供者,一般是module
    controllers必须创建的一组控制器,导入controlltr
    providers由 Nest 注入器实例化的提供者,并且可以至少在整个模块中共享,导入service
    exports由本模块提供并应在其他模块中可用的提供者的子集。一般导出service

路由

  • 熟悉koa2的人看到这可能想问,它的router在哪定义了呢,其实就是这个@Get,在最初的情况下,这个路由就是localhost:3000,如果稍作改动

// app.controller.ts import { Controller, Get } from '@nestjs/common'; import { AppService } from './app.service'; @Controller('hello') export class AppController {   constructor(private readonly appService: AppService) {}   @Get()   getHello(): string {     return this.appService.getHello();   } } 复制代码

  • 如果这个时候再访问localhost:3000,那就会报错

image.png

  • 此时输入localhost:3000/hello按下回车,hello world回来啦

image.png

  • 此时再做个修改

import { Controller, Get } from '@nestjs/common'; import { AppService } from './app.service'; @Controller('hello') export class AppController {   constructor(private readonly appService: AppService) {}   @Get('world')   getHello(): string {     return this.appService.getHello();   } } 复制代码

  • 如果这个时候再访问localhost:3000/hello,那就会报错

image.png

  • 此时输入localhost:3000/hello/world按下回车,hello world又回来啦

image.png

  • 其实这个controller.ts文件就相当于了路由,Controller装饰器中的hello,相当于这一整个路由的前缀,而Get装饰器中的world就是get请求的这条路由的路径,整个合起来就是localhost:3000/hello/world,这就是nestjs的路由

全局路由前缀

  • 其实在公司中,一般都有api为开头的接口,那在每个controller.ts文件加这个前缀就太麻烦了,可以选择在main.ts文件中使用setGlobalPrefix设置全局路由前缀

// main.ts import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; async function bootstrap() {   const app = await NestFactory.create(AppModule);   // 设置全局路由前缀   app.setGlobalPrefix('api');   await app.listen(3000); } bootstrap(); 复制代码

swagger

安装

  • 作为一个后端服务,API文档是必不可少的,Nest自带了Swagger文档,集成非常简单,在使用前需要安装依赖

npm install --save @nestjs/swagger 复制代码

使用

  • src目录下创建swagger.ts(根据自己习惯,我更喜欢将swagger抽离到单独的文件,main.ts越简洁越好,当然你也可以在main.ts中使用swagger

// swagger.ts import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger'; import * as packageConfig from '../package.json'; export const generateDocument = (app) => {   // 创建swagger接口文档   const options = new DocumentBuilder()     .setTitle(packageConfig.name) // 标题     .setDescription(packageConfig.description) // 描述     .setVersion(packageConfig.version) // 版本     .addBearerAuth()     .build();   const document = SwaggerModule.createDocument(app, options);   SwaggerModule.setup('/api/swagger', app, document); // 第一个参数是接口文档地址 }; 复制代码

  • 为了节约配置项,Swagger 的配置信息全部取自 package.json,有额外需求的话可以自己维护配置信息的文件

  • 需要注意默认情况下,在 TS 开发的项目中是没办法导入 .json 后缀的模块,在上文中import * as packageConfig from '../package.json',引入了json,需要在tsconfig.json文件中加上"resolveJsonModule": true

image.png

  • 然后在main.ts中进行使用

import { NestFactory } from '@nestjs/core'; import { AppModule } from '@/modules/app.module'; import { generateDocument } from './swagger'; async function bootstrap() {   const app = await NestFactory.create(AppModule);   // 设置全局路由前缀   app.setGlobalPrefix('api');   // 创建swagger文档   generateDocument(app);   await app.listen(+process.env.SERVICE_PORT, () => {     console.log(`项目运行在http:localhost:${process.env.SERVICE_PORT}/api`);   }); } bootstrap(); 复制代码

  • 打开http://localhost:1231/api/swagger,即可见swagger

image.png

  • 如果要做到如上图所示,我们需要用到几个swagger的装饰器

    • ApiTags:设置swagger文档标签分类

    • ApiOperation:接口描述信息

// user.controller.ts import {   Controller,   Get,   Post,   Body,   Patch,   Param,   Delete, } from '@nestjs/common'; import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { UserService } from './user.service'; import { CreateUserDto } from './dto/create-user.dto'; import { UpdateUserDto } from './dto/update-user.dto'; // 设置swagger文档标签分类 @ApiTags('用户模块') @Controller('user') export class UserController {   constructor(private readonly userService: UserService) {}   @Post('create')   @ApiOperation({     summary: '添加用户', // 接口描述信息   })   create(@Body() createUserDto: CreateUserDto) {     return this.userService.create(createUserDto);   }   @Get('list')   @ApiOperation({     summary: '获取user列表',   })   findAll() {     return this.userService.findAll();   }   @Get('list/:id')   @ApiOperation({     summary: '根据id获取user',   })   findOne(@Param('id') id: string) {     return this.userService.findOne(+id);   }   @Patch('list/:id')   @ApiOperation({     summary: '根据id修改user',   })   update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {     return this.userService.update(+id, updateUserDto);   }   @Delete('list/:id')   @ApiOperation({     summary: '根据id删除user',   })   remove(@Param('id') id: string) {     return this.userService.remove(+id);   } } 复制代码

总结

  • 本文对Nest进行介绍其创建项目、快捷命令、目录结构主要文件的作用、如何启动项目、使用swagger的方法

  • 下一篇:mysql数据库连接、登录验证(jwt),权限校验


作者:熠熠星河
链接:https://juejin.cn/post/7170116709846614052

文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐