美文网首页
跟随官网学nestjs之入门

跟随官网学nestjs之入门

作者: cc_licc | 来源:发表于2021-03-15 17:10 被阅读0次

    起步

    Nest 是一个用于构建高效,可扩展的 Node.js 服务器端应用程序的框架。

    安装

    可以使用官方提供的 cli 构建项目,也可以克隆启动项目

    • 使用 cli 安装
     npm i -g @nestjs/cli
     nest new nest-demo
    

    这个时候就已经初始化好了一个入门项目,打开项目,可以看到项目基本配置已经齐全,包含了 nest 核心文件

    src
    ├── app.controller.ts // 带有单个路由的基本控制器示例。
    ├── app.module.ts // 应用程序的根模块。
    └── main.ts // 应用程序入口文件。它使用 NestFactory 用来创建 Nest 应用实例。
    
    • 运行项目
    yarn start
    

    访问 http://localhost:3000,就可以看到 Hello World!。最简单的架子就已经好了,现在就是学习 nest 它提供的方法api

    控制器

    控制器负责处理传入的 请求 和向客户端返回 响应 ,就是我们所说的 controller 层。

    路由

    nest 实现路由,需要用到 @Controller() 装饰器,可以为其设置前缀,使用路径前缀可以对一组相关的路由进行分组,接下来将会用一个例子 user 模块完成

    • 使用 cli 内置命令创建一个 controller
    nest g controller user
    

    这时就会看到项目里已经有了 user 文件

    import { Controller, Get } from '@nestjs/common';
    
    @Controller('user')
    export class UserController {
    
      @Get()
      findOne(): string {
        return 'this is user controller';
      }
    }
    

    其中 @Get() 是一个装饰器,告诉我们这个方法是 HTTPget 请求,那么我们参数如何传递,这时就需要用到其他的装饰器。
    我们重启一下服务,在浏览器输入 http://localhost:3000/user,就能看到页面显示的 this is user controller。我们也可以使用 yarn start:dev 命令来热更新,就不用每次更改代码后重启服务。

    路由参数

    nest 提供 @Param()@Body() 等等装饰器,我们改造一下刚刚,提供一个根据 id 查询用户的接口

    import { Controller, Get, Param } from '@nestjs/common';
    
    @Controller('user')
    export class UserController {
    
      @Get(':id')
      findOne(@Param('id') id: string): string {
        return `find a user by id = ${id}`;
      }
    }
    

    在浏览器输入 http://localhost:3000/user/1,就能看到 find a user by id = 1。这就是使用路由 params 参数,当然使用 query 也是可以的;我们增加一个查询列表的接口

      @Get()
      findAll(
        @Query('pageIndex') pageIndex: number,
        @Query('pageSize') pageSize: number,
      ): string {
        return `find user list, pageIndex = ${pageIndex}, pageSize = ${pageSize}`;
      }
    

    这时在浏览器输入 http://localhost:3000/user?pageSize=10&pageIndex=1,就会看见 find user list, pageIndex = 1, pageSize = 10

    API 文档

    OpenAPI(Swagger)规范是一种用于描述 RESTful API 的强大定义格式。 Nest 提供了一个专用模块来使用它。

    安装

    $ npm install --save @nestjs/swagger swagger-ui-express
    

    引导

    安装过程完成后,打开根目录文件 main.ts,并使用 SwaggerModule 类初始化 Swagger

    import { NestFactory } from '@nestjs/core';
    import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
    import { AppModule } from './app.module';
    
    async function bootstrap() {
      const app = await NestFactory.create(AppModule);
      const options = new DocumentBuilder()
        .setTitle('nest demo example')
        .setDescription('The nest demo API description')
        .setVersion('1.0')
        .build();
      const document = SwaggerModule.createDocument(app, options);
    
      SwaggerModule.setup('api-docs', app, document);
    
      await app.listen(3000);
    }
    bootstrap();
    

    这时访问 http://localhost:3000/api-docs/ 就能看见如下的 Swagger UI 界面:

    img

    我们删除项目中 app 模块多余的代码,为当前 user 模块打上标签

    删除 app.service.tsapp.controller.ts,修改 app.module.ts

    import { Module } from '@nestjs/common';
    import { UserController } from './user/user.controller';
    
    @Module({
      imports: [],
      controllers: [UserController],
      providers: [],
    })
    export class AppModule {}
    

    user.controller.ts 加上 ApiTigs 告诉查看文档的人这个user模块,nestjs/swagger 提供了一系列内置注解方法,可以给接口添加更多的描述,便于使用者能更好的阅读理解接口

    import { Controller, Get, Param, Query } from '@nestjs/common';
    import { ApiTags, ApiOperation } from '@nestjs/swagger';
    
    @ApiTags('user')
    @Controller('user')
    export class UserController {
    
      @ApiOperation({
        summary: 'find a user by id',
      })
      @Get(':id')
      findOne(@Param('id') id: string): string {
        return `find a user by id = ${id}`;
      }
    
      @ApiOperation({
        summary: 'find user list',
      })
      @Get()
      findAll(
        @Query('pageIndex') pageIndex: number,
        @Query('pageSize') pageSize: number,
      ): string {
        return `find user list, pageIndex = ${pageIndex}, pageSize = ${pageSize}`;
      }
    }
    

    这时刷新浏览器,就能看到文档更新了

    img

    swagger 的好处就是我们可以使用它的 try it out 来模拟真实发起请求,也能看到请求需要的参数以及请求返回的数据,比 postman 更方便,而且我们还可以写上参数示例。

    SwaggerModule 在路由处理程序中查找所有使用的 @Body()@Query()@Param() 装饰器来生成 API 文档。该模块利用反射创建相应的模型定义,比如我们新增一个创建用户的接口

    新建一个 dto

    import { ApiProperty } from '@nestjs/swagger';
    
    export class CreateUserDto {
      @ApiProperty({ example: 'username' })
      readonly username: string;
    
      @ApiProperty({ example: 18 })
      readonly age: number;
    
      @ApiProperty({ example: 1 })
      readonly sex: number;
    
      @ApiProperty({ example: 'address' })
      readonly address: string;
    }
    

    user.controller.ts 新增创建接口

    ...
      @ApiOperation({
        summary: 'create a user',
      })
      @Post()
      create(
        @Body() createUserDto: CreateUserDto,
      ): string {
        return `create user, the user name = ${createUserDto.username}`;
      }
    ...
    

    刷新接口文档,就能看见新增了一个接口,基于 CreateUserDto 将创建模块定义:

    img

    其中我们使用 ApiProperty 装饰器来说明改字段的属性,更多用法可以查阅官方文档

    数据库

    官方提供几种数据库模型,这里我使用的是 Sequelize

    Sequelize 是一个用普通 JavaScript 编写的流行对象关系映射器( ORM ),但是有一个 Sequelize-TypeScript 包装器,它为基本 Sequelize 提供了一组装饰器和其他附加功能。

    安装

    $ npm install --save sequelize sequelize-typescript mysql2 @nestjs/sequelize
    $ npm install --save-dev @types/sequelize
    

    模型注入

    Sequelize 中,模型在数据库中定义了一个表。该类的实例表示数据库行。首先,我们至少需要一个实体 user.model.ts

    import {
      Column,
      Model,
      Table,
      TableOptions,
      DataType,
      CreatedAt,
      UpdatedAt,
    } from 'sequelize-typescript';
    
    const tableOptions: TableOptions = {
      tableName: 'user',
    };
    
    @Table(tableOptions)
    export class User extends Model<User> {
      @Column({
        type: DataType.BIGINT,
        allowNull: false,
        autoIncrement: true,
        primaryKey: true,
      })
      public id: number;
    
      @Column({
        type: DataType.STRING,
        allowNull: false,
      })
      username: string;
    
      @Column({
        type: DataType.STRING,
        allowNull: true,
      })
      password: string;
    
      @Column({
        type: DataType.STRING,
        allowNull: false,
      })
      address: string;
    
      @Column({
        type: DataType.BIGINT,
        allowNull: false,
      })
      age: number;
    
      @Column({
        type: DataType.BIGINT,
        allowNull: false,
      })
      sex: number;
    
      @CreatedAt public createdAt: Date;
    
      @UpdatedAt public updatedAt: Date;
    }
    

    该实体的定义,对应的就是映射到数据库的模型。新建 user.module.ts 来注入该模型

    import { Module } from '@nestjs/common';
    import { SequelizeModule } from '@nestjs/sequelize';
    import { UserController } from './user.controller';
    import { User } from './user.model';
    
    @Module({
      imports: [
        SequelizeModule.forFeature([User]),
      ],
      providers: [],
      controllers: [UserController],
      exports: [],
    })
    export class UserModule {}
    

    连接数据库

    我们在根节点实例化,并连接数据库

    import { Module } from '@nestjs/common';
    import { SequelizeModule } from '@nestjs/sequelize';
    import { UserModule } from './user/user.module';
    import { User } from './user/user.model';
    import { UserController } from './user/user.controller';
    
    @Module({
      imports: [
        UserModule,
        SequelizeModule.forRoot({
          dialect: 'mysql',
          host: 'localhost',
          port: 3306,
          username: 'root',
          password: 'root',
          database: 'nest_demo',
          models: [User],
        }),
      ],
      controllers: [],
      providers: [],
    })
    export class AppModule {}
    

    我们创建服务层,新建 user.service.ts

    import { Injectable } from '@nestjs/common';
    import { InjectModel } from '@nestjs/sequelize';
    import { User } from './user.model';
    import { CreateUserDto } from './dto';
    
    @Injectable()
    export class UserService {
    
      constructor(
        @InjectModel(User)
        private userModel: typeof User,
      ) {}
    
      async create(createUserDto: CreateUserDto): Promise<User> {
        const user = new User();
        user.username = createUserDto.username;
        user.age = createUserDto.age;
        user.address = createUserDto.address;
        user.sex = createUserDto.sex;
    
        return await user.save();
      }
    
      async findAll(): Promise<User[]> {
        return await this.userModel.findAll<User>({
          attributes: ['id', 'username', 'address', 'age', 'sex'],
        });
      }
    
      async findOneById(id: string): Promise<User> {
        return await this.userModel.findOne<User>({
          where: { id },
          attributes: ['id', 'username', 'address', 'age', 'sex'],
        });
      }
    }
    

    然后修改 controller

    import { Controller, Get, Param, Query, Post, Body } from '@nestjs/common';
    import { ApiTags, ApiOperation } from '@nestjs/swagger';
    import { CreateUserDto } from './dto';
    import { UserService } from './user.service';
    import { User } from './user.model';
    
    @ApiTags('user')
    @Controller('user')
    export class UserController {
      constructor(private readonly userService: UserService) {}
    
      @ApiOperation({
        summary: 'find a user by id',
      })
      @Get(':id')
      findOne(@Param('id') id: string): Promise<User> {
        return this.userService.findOneById(id);
      }
    
      @ApiOperation({
        summary: 'find user list',
      })
      @Get()
      findAll(): Promise<User[]> {
        return this.userService.findAll();
      }
    
      @ApiOperation({
        summary: 'create a user',
      })
      @Post()
      create(
        @Body() createUserDto: CreateUserDto,
      ): Promise<User> {
        return this.userService.create(createUserDto);
      }
    }
    

    这时访问文档,我们执行一下查询接口,就可以看到返回的数据结果了

    img

    到此,Nest 入门已经结束了,接下来我们会介绍简单的守卫

    代码传送门:nest-demo

    参考资料:Nest 文档

    相关文章

      网友评论

          本文标题:跟随官网学nestjs之入门

          本文链接:https://www.haomeiwen.com/subject/mgwkcltx.html