NestJS 简介
NestJS 是基于 TypeScript 的渐进式 Node.js 框架,用于构建高效、可靠、可扩展的服务器端应用。它融合了面向对象编程、函数式编程和响应式编程的最佳实践,为开发者提供了一种结构化的方式来构建复杂的后端应用。
核心特点
- 模块化架构:NestJS 采用模块化设计,使代码组织更加清晰,便于维护和扩展。
- 依赖注入:内置依赖注入系统,简化了组件之间的依赖管理。
- 装饰器支持:利用 TypeScript 装饰器,使代码更加简洁易读。
- TypeScript 集成:完全支持 TypeScript,提供类型安全和更好的开发体验。
- GraphQL 支持:内置对 GraphQL 的支持,便于构建现代 API。
- 微服务架构:支持构建微服务应用,适应现代云原生架构。
- 测试友好:内置测试工具和最佳实践,便于编写单元测试和集成测试。
安装与配置
安装 NestJS CLI
NestJS 提供了命令行工具,用于快速创建和管理项目:
# 全局安装 NestJS CLI
npm install -g @nestjs/cli
# 检查安装是否成功
nest --version创建第一个 NestJS 应用
使用 NestJS CLI 创建新项目:
# 创建新项目
nest new nestjs-demo
# 进入项目目录
cd nestjs-demo
# 启动开发服务器
npm run start:dev项目结构
创建的 NestJS 项目默认包含以下结构:
├── src/
│ ├── app.controller.spec.ts
│ ├── app.controller.ts
│ ├── app.module.ts
│ ├── app.service.ts
│ └── main.ts
├── test/
├── nest-cli.json
├── package.json
├── tsconfig.json
└── README.md- main.ts:应用程序入口文件,负责启动 NestJS 应用。
- app.module.ts:根模块,组织和管理其他模块。
- app.controller.ts:处理 HTTP 请求,定义路由。
- app.service.ts:业务逻辑层,处理具体的业务逻辑。
核心概念
模块 (Modules)
模块是 NestJS 应用的基本组织单位,用于组织代码和管理依赖。
// cats.module.ts
import { Module } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';
@Module({
controllers: [CatsController],
providers: [CatsService],
exports: [CatsService],
})
export class CatsModule {}控制器 (Controllers)
控制器负责处理 HTTP 请求,定义路由和请求处理逻辑。
// cats.controller.ts
import { Controller, Get, Post, Body, Param } from '@nestjs/common';
import { CatsService } from './cats.service';
import { CreateCatDto } from './dto/create-cat.dto';
import { Cat } from './interfaces/cat.interface';
@Controller('cats')
export class CatsController {
constructor(private readonly catsService: CatsService) {}
@Post()
async create(@Body() createCatDto: CreateCatDto): Promise<Cat> {
return this.catsService.create(createCatDto);
}
@Get()
async findAll(): Promise<Cat[]> {
return this.catsService.findAll();
}
@Get(':id')
async findOne(@Param('id') id: string): Promise<Cat> {
return this.catsService.findOne(id);
}
}提供者 (Providers)
提供者是 NestJS 中可以被注入的对象,如服务、仓库、工厂等,用于处理业务逻辑。
// cats.service.ts
import { Injectable } from '@nestjs/common';
import { Cat } from './interfaces/cat.interface';
import { CreateCatDto } from './dto/create-cat.dto';
@Injectable()
export class CatsService {
private readonly cats: Cat[] = [];
create(cat: CreateCatDto): Cat {
this.cats.push(cat);
return cat;
}
findAll(): Cat[] {
return this.cats;
}
findOne(id: string): Cat {
return this.cats.find(cat => cat.id === id);
}
}数据传输对象 (DTOs)
DTOs 用于定义数据传输的结构,确保数据的有效性和一致性。
// create-cat.dto.ts
export class CreateCatDto {
readonly name: string;
readonly age: number;
readonly breed: string;
}中间件 (Middleware)
中间件是处理请求和响应的函数,可以在路由处理之前或之后执行。
// logger.middleware.ts
import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';
@Injectable()
export class LoggerMiddleware implements NestMiddleware {
use(req: Request, res: Response, next: NextFunction) {
console.log(`${new Date().toISOString()} - ${req.method} ${req.url}`);
next();
}
}异常过滤器 (Exception Filters)
异常过滤器用于捕获和处理应用中的异常,提供统一的错误处理机制。
// http-exception.filter.ts
import { ExceptionFilter, Catch, ArgumentsHost, HttpException } from '@nestjs/common';
import { Request, Response } from 'express';
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
const request = ctx.getRequest<Request>();
const status = exception.getStatus();
response
.status(status)
.json({
statusCode: status,
timestamp: new Date().toISOString(),
path: request.url,
message: exception.message,
});
}
}实用案例分析
构建 RESTful API
下面是一个使用 NestJS 构建 RESTful API 的示例,实现了基本的 CRUD 操作。
项目结构
├── src/
│ ├── cats/
│ │ ├── dto/
│ │ │ ├── create-cat.dto.ts
│ │ │ └── update-cat.dto.ts
│ │ ├── interfaces/
│ │ │ └── cat.interface.ts
│ │ ├── cats.controller.ts
│ │ ├── cats.service.ts
│ │ └── cats.module.ts
│ ├── app.module.ts
│ └── main.ts
└── package.json代码实现
- 定义接口 (
cats/interfaces/cat.interface.ts):
export interface Cat {
id: string;
name: string;
age: number;
breed: string;
}- 定义 DTOs:
// cats/dto/create-cat.dto.ts
export class CreateCatDto {
readonly name: string;
readonly age: number;
readonly breed: string;
}
// cats/dto/update-cat.dto.ts
export class UpdateCatDto {
readonly name?: string;
readonly age?: number;
readonly breed?: string;
}- 实现服务 (
cats/cats.service.ts):
import { Injectable, NotFoundException } from '@nestjs/common';
import { Cat } from './interfaces/cat.interface';
import { CreateCatDto } from './dto/create-cat.dto';
import { UpdateCatDto } from './dto/update-cat.dto';
import { v4 as uuidv4 } from 'uuid';
@Injectable()
export class CatsService {
private readonly cats: Cat[] = [];
create(createCatDto: CreateCatDto): Cat {
const cat: Cat = {
id: uuidv4(),
...createCatDto,
};
this.cats.push(cat);
return cat;
}
findAll(): Cat[] {
return this.cats;
}
findOne(id: string): Cat {
const cat = this.cats.find(cat => cat.id === id);
if (!cat) {
throw new NotFoundException(`Cat with id ${id} not found`);
}
return cat;
}
update(id: string, updateCatDto: UpdateCatDto): Cat {
const cat = this.findOne(id);
const index = this.cats.findIndex(c => c.id === id);
this.cats[index] = { ...cat, ...updateCatDto };
return this.cats[index];
}
remove(id: string): void {
const index = this.cats.findIndex(cat => cat.id === id);
if (index === -1) {
throw new NotFoundException(`Cat with id ${id} not found`);
}
this.cats.splice(index, 1);
}
}- 实现控制器 (
cats/cats.controller.ts):
import { Controller, Get, Post, Put, Delete, Body, Param, HttpCode, HttpStatus } from '@nestjs/common';
import { CatsService } from './cats.service';
import { CreateCatDto } from './dto/create-cat.dto';
import { UpdateCatDto } from './dto/update-cat.dto';
import { Cat } from './interfaces/cat.interface';
@Controller('cats')
export class CatsController {
constructor(private readonly catsService: CatsService) {}
@Post()
@HttpCode(HttpStatus.CREATED)
create(@Body() createCatDto: CreateCatDto): Cat {
return this.catsService.create(createCatDto);
}
@Get()
findAll(): Cat[] {
return this.catsService.findAll();
}
@Get(':id')
findOne(@Param('id') id: string): Cat {
return this.catsService.findOne(id);
}
@Put(':id')
update(@Param('id') id: string, @Body() updateCatDto: UpdateCatDto): Cat {
return this.catsService.update(id, updateCatDto);
}
@Delete(':id')
@HttpCode(HttpStatus.NO_CONTENT)
remove(@Param('id') id: string): void {
this.catsService.remove(id);
}
}- 创建模块 (
cats/cats.module.ts):
import { Module } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';
@Module({
controllers: [CatsController],
providers: [CatsService],
exports: [CatsService],
})
export class CatsModule {}- 更新根模块 (
app.module.ts):
import { Module } from '@nestjs/common';
import { CatsModule } from './cats/cats.module';
@Module({
imports: [CatsModule],
})
export class AppModule {}- 启动应用 (
main.ts):
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(3000);
console.log(`Application is running on: ${await app.getUrl()}`);
}
bootstrap();测试 API
使用 curl 或 Postman 测试 API:
# 创建猫
curl -X POST http://localhost:3000/cats -H "Content-Type: application/json" -d '{"name": "Tom", "age": 3, "breed": "Siamese"}'
# 获取所有猫
curl http://localhost:3000/cats
# 获取单个猫
curl http://localhost:3000/cats/{id}
# 更新猫
curl -X PUT http://localhost:3000/cats/{id} -H "Content-Type: application/json" -d '{"age": 4}'
# 删除猫
curl -X DELETE http://localhost:3000/cats/{id}数据库集成
NestJS 支持多种数据库,包括 MongoDB、PostgreSQL、MySQL 等。下面以 MongoDB 为例,展示如何集成数据库。
安装依赖
# 安装 Mongoose 和相关依赖
npm install mongoose @nestjs/mongoose配置数据库连接
// app.module.ts
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { CatsModule } from './cats/cats.module';
@Module({
imports: [
MongooseModule.forRoot('mongodb://localhost:27017/nestjs-demo'),
CatsModule,
],
})
export class AppModule {}定义数据库模型
// cats/schemas/cat.schema.ts
import { Schema } from 'mongoose';
export const CatSchema = new Schema({
name: String,
age: Number,
breed: String,
});更新模块配置
// cats/cats.module.ts
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';
import { CatSchema } from './schemas/cat.schema';
@Module({
imports: [MongooseModule.forFeature([{ name: 'Cat', schema: CatSchema }])],
controllers: [CatsController],
providers: [CatsService],
exports: [CatsService],
})
export class CatsModule {}更新服务实现
import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { Cat } from './interfaces/cat.interface';
import { CreateCatDto } from './dto/create-cat.dto';
import { UpdateCatDto } from './dto/update-cat.dto';
@Injectable()
export class CatsService {
constructor(@InjectModel('Cat') private readonly catModel: Model<Cat>) {}
async create(createCatDto: CreateCatDto): Promise<Cat> {
const createdCat = new this.catModel(createCatDto);
return await createdCat.save();
}
async findAll(): Promise<Cat[]> {
return await this.catModel.find().exec();
}
async findOne(id: string): Promise<Cat> {
const cat = await this.catModel.findById(id).exec();
if (!cat) {
throw new NotFoundException(`Cat with id ${id} not found`);
}
return cat;
}
async update(id: string, updateCatDto: UpdateCatDto): Promise<Cat> {
const updatedCat = await this.catModel.findByIdAndUpdate(id, updateCatDto, { new: true }).exec();
if (!updatedCat) {
throw new NotFoundException(`Cat with id ${id} not found`);
}
return updatedCat;
}
async remove(id: string): Promise<void> {
const result = await this.catModel.findByIdAndDelete(id).exec();
if (!result) {
throw new NotFoundException(`Cat with id ${id} not found`);
}
}
}总结
NestJS 是一个现代化的 Node.js 框架,它结合了多种编程范式的最佳实践,为开发者提供了一种结构化、可扩展的方式来构建后端应用。通过本教程,你应该已经了解了 NestJS 的核心概念和基本用法,包括模块、控制器、提供者、DTOs、中间件、异常过滤器等。
NestJS 的模块化设计和依赖注入系统,使得代码组织更加清晰,便于维护和扩展。它对 TypeScript 的完全支持,提供了类型安全和更好的开发体验。此外,NestJS 还内置了对 GraphQL、微服务等现代技术的支持,适应了现代应用开发的需求。
要深入学习 NestJS,建议查阅 官方文档 和实践更多的项目案例,以掌握其高级特性和最佳实践。NestJS 的生态系统也在不断发展,有大量的第三方库和工具可供选择,可以进一步提高开发效率。