起步
Nest 是一個(gè)用于構(gòu)建高效,可擴(kuò)展的 Node.js 服務(wù)器端應(yīng)用程序的框架。
安裝
可以使用官方提供的 cli 構(gòu)建項(xiàng)目,也可以克隆啟動(dòng)項(xiàng)目
- 使用
cli安裝
npm i -g @nestjs/cli
nest new nest-demo
這個(gè)時(shí)候就已經(jīng)初始化好了一個(gè)入門項(xiàng)目,打開項(xiàng)目,可以看到項(xiàng)目基本配置已經(jīng)齊全,包含了 nest 核心文件
src
├── app.controller.ts // 帶有單個(gè)路由的基本控制器示例。
├── app.module.ts // 應(yīng)用程序的根模塊。
└── main.ts // 應(yīng)用程序入口文件。它使用 NestFactory 用來創(chuàng)建 Nest 應(yīng)用實(shí)例。
- 運(yùn)行項(xiàng)目
yarn start
訪問 http://localhost:3000,就可以看到 Hello World!。最簡單的架子就已經(jīng)好了,現(xiàn)在就是學(xué)習(xí) nest 它提供的方法api
控制器
控制器負(fù)責(zé)處理傳入的 請(qǐng)求 和向客戶端返回 響應(yīng) ,就是我們所說的 controller 層。
路由
在 nest 實(shí)現(xiàn)路由,需要用到 @Controller() 裝飾器,可以為其設(shè)置前綴,使用路徑前綴可以對(duì)一組相關(guān)的路由進(jìn)行分組,接下來將會(huì)用一個(gè)例子 user 模塊完成
- 使用
cli內(nèi)置命令創(chuàng)建一個(gè)controller
nest g controller user
這時(shí)就會(huì)看到項(xiàng)目里已經(jīng)有了 user 文件
import { Controller, Get } from '@nestjs/common';
@Controller('user')
export class UserController {
@Get()
findOne(): string {
return 'this is user controller';
}
}
其中 @Get() 是一個(gè)裝飾器,告訴我們這個(gè)方法是 HTTP 的 get 請(qǐng)求,那么我們參數(shù)如何傳遞,這時(shí)就需要用到其他的裝飾器。
我們重啟一下服務(wù),在瀏覽器輸入 http://localhost:3000/user,就能看到頁面顯示的 this is user controller。我們也可以使用 yarn start:dev 命令來熱更新,就不用每次更改代碼后重啟服務(wù)。
路由參數(shù)
nest 提供 @Param()、@Body() 等等裝飾器,我們改造一下剛剛,提供一個(gè)根據(jù) 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 參數(shù),當(dāng)然使用 query 也是可以的;我們?cè)黾右粋€(gè)查詢列表的接口
@Get()
findAll(
@Query('pageIndex') pageIndex: number,
@Query('pageSize') pageSize: number,
): string {
return `find user list, pageIndex = ${pageIndex}, pageSize = ${pageSize}`;
}
這時(shí)在瀏覽器輸入 http://localhost:3000/user?pageSize=10&pageIndex=1,就會(huì)看見 find user list, pageIndex = 1, pageSize = 10
API 文檔
OpenAPI(Swagger)規(guī)范是一種用于描述 RESTful API 的強(qiáng)大定義格式。 Nest 提供了一個(gè)專用模塊來使用它。
安裝
$ npm install --save @nestjs/swagger swagger-ui-express
引導(dǎo)
安裝過程完成后,打開根目錄文件 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();
這時(shí)訪問 http://localhost:3000/api-docs/ 就能看見如下的 Swagger UI 界面:

我們刪除項(xiàng)目中 app 模塊多余的代碼,為當(dāng)前 user 模塊打上標(biāo)簽
刪除 app.service.ts、app.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 告訴查看文檔的人這個(gè)user模塊,nestjs/swagger 提供了一系列內(nèi)置注解方法,可以給接口添加更多的描述,便于使用者能更好的閱讀理解接口
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}`;
}
}
這時(shí)刷新瀏覽器,就能看到文檔更新了

swagger 的好處就是我們可以使用它的 try it out 來模擬真實(shí)發(fā)起請(qǐng)求,也能看到請(qǐng)求需要的參數(shù)以及請(qǐng)求返回的數(shù)據(jù),比 postman 更方便,而且我們還可以寫上參數(shù)示例。
SwaggerModule 在路由處理程序中查找所有使用的 @Body() , @Query() 和 @Param() 裝飾器來生成 API 文檔。該模塊利用反射創(chuàng)建相應(yīng)的模型定義,比如我們新增一個(gè)創(chuàng)建用戶的接口
新建一個(gè) 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 新增創(chuàng)建接口
...
@ApiOperation({
summary: 'create a user',
})
@Post()
create(
@Body() createUserDto: CreateUserDto,
): string {
return `create user, the user name = ${createUserDto.username}`;
}
...
刷新接口文檔,就能看見新增了一個(gè)接口,基于 CreateUserDto 將創(chuàng)建模塊定義:

其中我們使用 ApiProperty 裝飾器來說明改字段的屬性,更多用法可以查閱官方文檔
數(shù)據(jù)庫
官方提供幾種數(shù)據(jù)庫模型,這里我使用的是 Sequelize。
Sequelize 是一個(gè)用普通 JavaScript 編寫的流行對(duì)象關(guān)系映射器( ORM ),但是有一個(gè) Sequelize-TypeScript 包裝器,它為基本 Sequelize 提供了一組裝飾器和其他附加功能。
安裝
$ npm install --save sequelize sequelize-typescript mysql2 @nestjs/sequelize
$ npm install --save-dev @types/sequelize
模型注入
在 Sequelize 中,模型在數(shù)據(jù)庫中定義了一個(gè)表。該類的實(shí)例表示數(shù)據(jù)庫行。首先,我們至少需要一個(gè)實(shí)體 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;
}
該實(shí)體的定義,對(duì)應(yīng)的就是映射到數(shù)據(jù)庫的模型。新建 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 {}
連接數(shù)據(jù)庫
我們?cè)诟?jié)點(diǎn)實(shí)例化,并連接數(shù)據(jù)庫
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 {}
我們創(chuàng)建服務(wù)層,新建 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);
}
}
這時(shí)訪問文檔,我們執(zhí)行一下查詢接口,就可以看到返回的數(shù)據(jù)結(jié)果了

到此,Nest 入門已經(jīng)結(jié)束了,接下來我們會(huì)介紹簡單的守衛(wèi)
代碼傳送門:nest-demo
參考資料:Nest 文檔