4. Nest.js 控制器:处理请求的艺术

345 阅读5分钟

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 来定义请求体的结构,并在 createupdate 方法中使用它。这样可以确保请求体的数据结构一致,便于维护和验证。

使用服务处理业务逻辑

在实际应用中,控制器通常不会直接处理业务逻辑,而是调用服务来完成这些任务。让我们为 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)。中间件是处理请求和响应的强大工具,可以在请求到达控制器之前或响应发送到客户端之前执行一些操作。敬请期待!