4. Nest.js 控制器:处理请求的艺术
介绍
欢迎回来!在前几篇文章中,我们已经了解了如何创建一个基本的 Nest.js 应用,并深入探讨了模块化架构。今天,我们将聚焦于控制器(Controller),它们是处理 HTTP 请求的关键角色。控制器就像是应用的“接待员”,负责接收请求、处理请求并返回响应。让我们一起探索控制器的艺术吧!
什么是控制器?
在 Nest.js 中,控制器是用来处理传入的请求并返回响应的。每个控制器负责处理特定的路由和请求方法(如 GET、POST、PUT、DELETE 等)。控制器通常会调用服务(Service)来处理业务逻辑,然后将结果返回给客户端。
创建一个控制器
让我们通过一个实际例子来了解控制器的工作原理。假设我们要创建一个用于管理书籍的控制器。
首先,使用 Nest CLI 创建一个新的控制器:
nest generate controller books
这条命令会在 src 目录下生成一个 books 目录,并在其中创建一个 books.controller.ts 文件。让我们看看这个文件的内容:
import { Controller, Get } from '@nestjs/common';
@Controller('books')
export class BooksController {
@Get()
findAll(): string {
return 'This action returns all books';
}
}
@Controller('books'):定义一个控制器,并指定路由前缀为books。@Get():定义一个 GET 请求的路由。findAll方法:处理 GET 请求并返回一个字符串。
添加更多路由和方法
控制器不仅可以处理 GET 请求,还可以处理其他类型的请求。让我们为 BooksController 添加更多的路由和方法。
修改 books.controller.ts 文件如下:
import { Controller, Get, Post, Put, Delete, Param, Body } from '@nestjs/common';
@Controller('books')
export class BooksController {
@Get()
findAll(): string {
return 'This action returns all books';
}
@Get(':id')
findOne(@Param('id') id: string): string {
return `This action returns a #${id} book`;
}
@Post()
create(@Body() createBookDto: any): string {
return 'This action adds a new book';
}
@Put(':id')
update(@Param('id') id: string, @Body() updateBookDto: any): string {
return `This action updates a #${id} book`;
}
@Delete(':id')
remove(@Param('id') id: string): string {
return `This action removes a #${id} book`;
}
}
@Get(':id'):定义一个带参数的 GET 请求路由。@Post():定义一个 POST 请求路由。@Put(':id'):定义一个带参数的 PUT 请求路由。@Delete(':id'):定义一个带参数的 DELETE 请求路由。@Param('id'):获取路由参数。@Body():获取请求体。
使用 DTO(数据传输对象)
在实际应用中,我们通常会使用 DTO(数据传输对象)来定义请求体的结构。让我们为 BooksController 创建一个 DTO。
首先,创建一个 create-book.dto.ts 文件:
export class CreateBookDto {
title: string;
author: string;
publishedDate: string;
}
然后,修改 books.controller.ts 文件,使用 DTO:
import { Controller, Get, Post, Put, Delete, Param, Body } from '@nestjs/common';
import { CreateBookDto } from './create-book.dto';
@Controller('books')
export class BooksController {
@Get()
findAll(): string {
return 'This action returns all books';
}
@Get(':id')
findOne(@Param('id') id: string): string {
return `This action returns a #${id} book`;
}
@Post()
create(@Body() createBookDto: CreateBookDto): string {
return `This action adds a new book with title: ${createBookDto.title}`;
}
@Put(':id')
update(@Param('id') id: string, @Body() updateBookDto: CreateBookDto): string {
return `This action updates a #${id} book with title: ${updateBookDto.title}`;
}
@Delete(':id')
remove(@Param('id') id: string): string {
return `This action removes a #${id} book`;
}
}
在这个例子中,我们使用 CreateBookDto 来定义请求体的结构,并在 create 和 update 方法中使用它。这样可以确保请求体的数据结构一致,便于维护和验证。
使用服务处理业务逻辑
在实际应用中,控制器通常不会直接处理业务逻辑,而是调用服务来完成这些任务。让我们为 BooksController 创建一个服务,并将业务逻辑移到服务中。
首先,使用 Nest CLI 创建一个新的服务:
nest generate service books
这条命令会在 books 目录下生成一个 books.service.ts 文件。让我们看看这个文件的内容:
import { Injectable } from '@nestjs/common';
@Injectable()
export class BooksService {
findAll(): string {
return 'This action returns all books';
}
findOne(id: string): string {
return `This action returns a #${id} book`;
}
create(createBookDto: any): string {
return `This action adds a new book with title: ${createBookDto.title}`;
}
update(id: string, updateBookDto: any): string {
return `This action updates a #${id} book with title: ${updateBookDto.title}`;
}
remove(id: string): string {
return `This action removes a #${id} book`;
}
}
接下来,我们需要将 BooksService 添加到 BooksModule 中。打开 books.module.ts 文件,修改如下:
import { Module } from '@nestjs/common';
import { BooksController } from './books.controller';
import { BooksService } from './books.service';
@Module({
controllers: [BooksController],
providers: [BooksService],
})
export class BooksModule {}
最后,修改 books.controller.ts 文件,使用 BooksService:
import { Controller, Get, Post, Put, Delete, Param, Body } from '@nestjs/common';
import { BooksService } from './books.service';
import { CreateBookDto } from './create-book.dto';
@Controller('books')
export class BooksController {
constructor(private readonly booksService: BooksService) {}
@Get()
findAll(): string {
return this.booksService.findAll();
}
@Get(':id')
findOne(@Param('id') id: string): string {
return this.booksService.findOne(id);
}
@Post()
create(@Body() createBookDto: CreateBookDto): string {
return this.booksService.create(createBookDto);
}
@Put(':id')
update(@Param('id') id: string, @Body() updateBookDto: CreateBookDto): string {
return this.booksService.update(id, updateBookDto);
}
@Delete(':id')
remove(@Param('id') id: string): string {
return this.booksService.remove(id);
}
}
在这个例子中,我们将业务逻辑移到了 BooksService 中,并在 BooksController 中调用相应的方法。这样可以使控制器更加简洁,专注于处理请求和响应。
运行应用
现在,我们已经完成了所有的配置。让我们运行应用并测试一下。
在项目根目录下运行以下命令:
npm run start
打开浏览器,访问以下 URL,测试不同的路由:
http://localhost:3000/books:返回 "This action returns all books"。http://localhost:3000/books/1:返回 "This action returns a #1 book"。- 使用 Postman 或其他工具发送 POST 请求到
http://localhost:3000/books,请求体为{ "title": "Nest.js", "author": "Kamil", "publishedDate": "2023" },返回 "This action adds a new book with title: Nest.js"。 - 使用 Postman 或其他工具发送 PUT 请求到
http://localhost:3000/books/1,请求体为{ "title": "Nest.js Updated", "author": "Kamil", "publishedDate": "2023" },返回 "This action updates a #1 book with title: Nest.js Updated"。 - 使用 Postman 或其他工具发送 DELETE 请求到 `http://localhost:3000/books/1
结论
在这篇文章中,我们深入探讨了 Nest.js 控制器的工作原理,并通过实际例子展示了如何创建和使用控制器。我们还学习了如何使用 DTO 来定义请求体的结构,以及如何将业务逻辑移到服务中,使控制器更加简洁和专注。
通过这些步骤,我们已经掌握了处理 HTTP 请求的基本技能,并了解了如何在 Nest.js 中组织代码,使其更加清晰和易于维护。在接下来的文章中,我们将继续深入探讨 Nest.js 的其他核心概念和功能,帮助你构建更强大和灵活的应用。
感谢你的阅读!如果你有任何问题或建议,欢迎在评论区留言。我们下次再见!
预告
在下一篇文章中,我们将探讨 Nest.js 中的中间件(Middleware)。中间件是处理请求和响应的强大工具,可以在请求到达控制器之前或响应发送到客户端之前执行一些操作。敬请期待!