美文网首页
跟随官网学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