Nest.js 小白入门初体验

前言:欢迎来到本篇博客文章,小编是一个刚刚接触 Nest.js 框架的新手,想通过这篇掘金推文记下笔记,加深一下个人的学习印象和分享一下学习到的知识点,如有错误之处烦请各位掘友在评论区指正谢谢。
首先,学习一门技术之前,通常要了解这个技术是什么,用来做什么的啦。Nest.js 是一个基于 TypeScript 的渐进式后端框架,它提供了一种现代化、可扩展的方式来构建 Node.js 应用程序。无论你是有经验的前端开发人员希望扩展到后端领域,还是一个全新的编程爱好者,本文都将带你了解 Nest.js 的基本概念和入门要点。小编将会在本篇以及后续的不断地更新推文中和大家一起探索 Nest.js 的模块化架构、依赖注入、控制器和服务等核心概念,并通过简单易懂的示例代码帮助你快速上手并编写简单的接口数据。本文旨在为你提供一个友好的起点,让你能够自信地开始在 Nest.js 中构建你的第一个后端应用程序。让我们一起开始这个令人兴奋的 Nest.js 之旅吧!
一. 基础工程
创建项目
js 复制代码
// 使用 [Nest CLI] 建立新项目非常简单。 在安装好 npm 后,
// 您可以使用下面命令在您的 OS 终端中创建 Nest 项目:
npm i -g @nestjs/cli

// project-name 为项目名称
nest new project-name

// 将会创建 `project-name` 目录, 安装 node_modules 和一些其他样板文件,
// 并将创建一个 `src` 目录,目录中包含几个核心文件。

src
├── app.controller.spec.ts 带有单个路由的基本控制器示例。
├── app.controller.ts 对于基本控制器的单元测试样例
├── app.module.ts 应用程序的根模块。
├── app.service.ts 带有单个方法的基本服务
└── main.ts 应用程序入口文件。它使用 `NestFactory` 用来创建 Nest 应用实例。

// 安装过程完成后,您可以在系统命令行工具中运行以下命令,以启动应用程序
npm run start
二. 模块化架构
2.1 概念:模块化架构是 Nest.js 框架的一个核心概念,它帮助开发者将应用程序划分为独立的、可重用的模块,以提高代码的组织性、可维护性和可扩展性。每个模块都有自己的功能范围,可以包含控制器、服务、管道、中间件和其他相关的组件。
2.2 优势:
  1. 代码组织:模块化架构使得项目结构清晰明了,可以将相关的功能组织在一起,使代码更易于理解和维护。
  2. 可重用性:模块可以被多个应用程序和其他模块重用,提高了代码的可重用性和可测试性。
  3. 解耦和解藕:模块之间的依赖关系可以通过模块化架构进行解耦和解藕,使得修改一个模块不会对其他模块造成影响。
2.3 假设我们正在开发一个博客应用程序,我们可以将应用程序划分为以下几个模块
js 复制代码
1.  `UserModule`(用户模块):该模块负责处理与用户相关的功能,例如用户的注册、登录、个人资料管理等。
    它可以包含 `UserController`(用户控制器)和 `UserService`(用户服务)等组件。
    
2.  `PostModule`(文章模块):该模块负责处理与文章相关的功能,例如文章的创建、编辑、删除等。
    它可以包含 `PostController`(文章控制器)和 `PostService`(文章服务)等组件。
3.  `CommentModule`(评论模块):该模块负责处理与评论相关的功能,例如评论的添加、删除、获取等。
    它可以包含 `CommentController`(评论控制器)和 `CommentService`(评论服务)等组件。
2.4示例
js 复制代码
// 通过如下命令实现 cats 模块
nest g controller cats

// 通过生成 `cats` 控制器,Nest.js 创建了一个包含控制器的模块。这个模块可以包含其他与猫咪功能相关
// 的组件,例如服务、提供者、DTO(数据传输对象)等。我们可以根据需要在 `cats` 模块中添加其他组件,
// 以满足应用程序的需求。
2.5 总结
  1. 每个模块都有自己的职责范围,并且它们可以独立开发、测试和部署。在应用程序的主模块中,我们可以将这些模块进行导入和配置,以建立它们之间的关系。

  2. 通过模块化架构,我们能够更好地组织应用程序的代码,并提供了一种灵活的方式来扩展和维护应用程序。每个模块都可以专注于特定的功能领域,使得开发变得更加模块化和可扩展。

三. 依赖注入
3.1 概念: 依赖注入(Dependency Injection,简称 DI)是一种设计模式和编程技术,用于实现模块之间的解耦和组件的可替换性。在 Nest.js 中,依赖注入是一种核心的概念,用于管理和注入模块之间的依赖关系。
3.2 下面是一些详细的讲解关于依赖注入模块的重要概念:
js 复制代码
1.  提供者(Providers):提供者是依赖注入模块中的组件,它们负责创建和提供依赖项的实例。
    在 Nest.js 中,提供者可以是类、工厂函数、常量或外部模块的引用。提供者可以在模块中
    通过 `providers` 属性进行注册。
    
2.  注入器(Injector):注入器是依赖注入模块的核心,它负责创建和管理依赖项的实例,并将
    它们注入到需要它们的地方。注入器根据提供者的定义,自动解析和实例化依赖项,并在需要
    时将它们注入到构造函数、方法参数或属性中。
    
3.  模块定义(Module Definition):依赖注入模块通过使用 `@Module()` 装饰器进行定义。
    模块定义包括模块的元数据和配置,例如要导入的其他模块、要导出的提供者列表以及要提供
    的全局作用域。
    
4.  导入(Imports):模块可以通过 `imports` 属性导入其他模块,以便共享其提供者和功能。
    这样可以构建出具有层次结构的模块体系,使应用程序更加模块化和可扩展。
    
5.  导出(Exports):模块可以通过 `exports` 属性导出提供者,以便其他模块可以访问和使用
    这些提供者。导出的提供者可以在其他模块中进行注入和使用,促进了模块之间的解耦和组件的可重用性。
3.2 示例
js 复制代码
   1. 图一通过将 `@Injectable()` 装饰器应用在 `ResponseInterceptor` 类上,你明确地将这个类标记
   为一个可注入的提供者,符合依赖注入的思想。这样,Nest.js 就可以正确地创建和
   管理 `ResponseInterceptor` 类的实例,并将其注入到其他需要它的地方。
   `这样,所有经过这个拦截器的响应数据都会被统一格式化,包含状态码、消息和原始数据。`
   
   2. 图二使用了 Nest.js 提供的 `@Injectable()` 装饰器来标记 `LoggingInterceptor` 类作为一个
     可注入的提供者。
     `这个拦截器的主要作用是在处理请求之前,记录请求的方法和 URL,以便进行日志记录和跟踪。`

   3. 图三. 在代码示例中使用了依赖注入的概念。在`AppModule`类的`providers`数组中,提供了两个拦截器
     作为依赖注入的提供者(Providers)。使用`provide`属性来指定提供者的令牌,这里使用了`APP_INTERCEPTOR`常量,
     它是Nest.js提供的一个内置令牌,用于标识应用程序级别的拦截器。然后,我使用`useClass`属性指定 
     了要注入的实际类,分别是`ResponseInterceptor`和`LoggingInterceptor`。

   4。 通过这样的配置,Nest.js将会在需要拦截器的地方自动注入这两个拦截器的实例。
    例如,在图三的 `controllers`数组中列出的`AppController`和`CatsController`,如果
    它们在请求处理过程中需要拦截器,Nest.js将会注入这两个拦截器的实例。
    
四. 控制器
4.1 概念:控制器(Controller)是 Nest.js 框架中的一个核心概念,它用于处理接收到的请求并生成响应。控制器作为应用程序的一部分,负责处理特定的路由和请求,以及协调其他组件(如服务、拦截器等)来完成请求的处理和生成响应。
4.2 作用:控制器的主要作用是定义路由处理程序,也就是用于处理特定路由的函数或方法。通过使用装饰器来标记控制器类和控制器方法,Nest.js 可以自动将路由与相应的处理程序关联起来,并在接收到请求时调用适当的处理程序。
js 复制代码
以下是控制器的一些作用的详细说明:

1.  处理 HTTP 请求:控制器可以用于处理不同的 HTTP 请求方法(如 GET、POST、PUT、DELETE 等)和路由。
    通过定义不同的路由处理程序,控制器可以根据接收到的请求执行相应的操作。例如,个 `UserController` 
    控制器可以定义 `GET /users` 路由来获取用户列表,以及 `POST /users` 路由来创建新用户。
    
2.  调用服务:控制器可以协调调用其他服务来完成业务逻辑的处理。通过将服务注入到控制器的构造函数中,
    并在控制器方法中使用这些服务,可以实现对数据的处理、业务逻辑的执行等。例如,在上述的用户列表
    示例中,`UserController` 控制器可以调用一个 `UserService` 来获取用户数据、创建新用户等操作。
    
3.  返回响应:控制器负责生成并返回适当的响应给客户端。通过在控制器方法中使用 `@HttpCode`、
    `@Headers`、`@Redirect`、`@Res` 等装饰器来设置响应的状态码、头部信息、重定向等。
    控制器方法可以返回普通对象、Promise、Observable 等,Nest.js 会根据返回值自动处理
    并生成最终的响应。

让我们通过一个示例来说明这一点:(重点是理解路由与相应的处理程序之间的关系,就和我们在 Vue 或者 react 中理解的路由一样,它是一种映射关系,不同的路由(接口)就会对应不同的处理逻辑(接口逻辑))

js 复制代码
import { Controller, Get, Post } from '@nestjs/common';

@Controller('users')
export class UserController {
  @Get()
  getUsers() {
    return 'Get users';
  }

  @Post()
  createUser() {
    return 'Create user';
  }
}

在上述示例中,我们创建了一个名为 UserController 的控制器类,并使用 @Controller('users') 装饰器指定了该控制器处理的路由前缀为 /users。

控制器类中定义了两个方法:getUsers() 和 createUser()。我们使用 @Get() 装饰器标记了 getUsers() 方法,表示它处理 GET 请求。同样,我们使用 @Post() 装饰器标记了 createUser() 方法,表示它处理 POST 请求。

现在,假设应用程序收到了一个 GET 请求,路径为 /users。Nest.js 将会自动调用 UserController 中的 getUsers() 方法来处理该请求。该方法返回字符串 'Get users',这将作为响应发送回客户端。

同样,如果收到一个 POST 请求,路径也为 /users,Nest.js 将会调用 UserController 中的 createUser() 方法来处理该请求。该方法返回字符串 'Create user',作为响应返回给客户端。

通过这种方式,控制器定义了路由处理程序,指定了相应的请求方法和路由路径。当应用程序接收到匹配的请求时,Nest.js 会自动调用相应的方法来处理请求并生成响应。这样,我们可以通过控制器来定义和组织应用程序的路由处理逻辑。

五. 编写简单的接口逻辑
5.1 以下是小编实现的一个控制器,里面包含一些接口,并定义了相关请求的返回数据
5.2 分析:
js 复制代码
1.  控制器装饰器:`@Controller('cats')`

    -   这个装饰器将控制器类 `CatsController` 与 `/cats` 路径关联起来。也就是说,
        该控制器将处理与 `/cats` 路径相关的请求。

1.  路由处理方法:

    -   `create()` 方法:使用 `@Post()` 装饰器标记,处理 POST 请求到 `/cats` 路径。
        它接收一个 `createCatDto` 对象作为请求体,并使用 `uuidv4()` 生成一个新的唯一 ID。
        然后,它返回一个包含新创建的猫咪对象的响应。
        
    -   `findOneByQuery()` 方法:使用 `@Get()` 装饰器标记,处理 GET 请求到 `/cats/id=18`(18只是
        一个示例,表示以这种格式上传的意思) 的路径。它使用 `@Query('id')` 装饰器获取查询参数
        `id` 的值,并返回一个包含查询到的猫咪对象的响应。
        
    -   `findOneByParam()` 方法:使用 `@Get(':id')` 装饰器标记,处理 GET 请求到 `/cats/{id}` 路
        径。它使用 `@Param('id')` 装饰器获取路径参数 `id` 的值,并返回一个包含查询到的猫咪对象的响应。
        
    -   `findAll()` 方法:使用 `@Get()` 装饰器标记,处理 GET 请求到 `/cats` 路径。它返回一个包含
        字符串 `'hello World!!!'` 的响应。
        
    -   `update()` 方法:使用 `@Put(':id')` 装饰器标记,处理 PUT 请求到 `/cats/{id}` 路径。它
        使用 `@Param('id')` 装饰器获取路径参数 `id` 的值,并使用 `@Body()` 装饰器获取请求体中
        的数据。然后,它返回一个包含更新后的猫咪对象的响应。
        
    -   `remove()` 方法:使用 `@Delete(':id')` 装饰器标记,处理 DELETE 请求到 `/cats/{id}` 路径。
        它使用 `@Param('id')` 装饰器获取路径参数 `id` 的值,并返回一个包含被删除的猫咪对象的响应。

1.  响应处理:

    -   在每个路由处理方法中,使用 `res.status(HttpStatus.XXX).json(data)` 将包含状态码、
        消息和数据的响应发送给客户端。这里使用了 `HttpStatus` 枚举来设置状态码。
5.3 cats.controller.ts的完整代码以及小编在试错过程中加入的一些必要注释
js 复制代码
import {
  Controller,
  Get,
  Post,
  Put,
  Delete,
  Param,
  Body,
  HttpStatus,
  Res,
  Query,
} from '@nestjs/common';
import { CreateCatDto, UpdateCatDto } from './create-cat.dto';
import { Response } from 'express';
import { v4 as uuidv4 } from 'uuid';

@Controller('cats')
export class CatsController {
  @Post()
  // @HttpCode(200) //子定义响应状态码
  // @Header('Cache-Control', 'none') //子定义响应头
  async create(
    @Body() createCatDto: CreateCatDto,
    @Res({ passthrough: true }) res: Response,
  ) {
    console.log('createCatDto', createCatDto);
    const cat = {
      id: uuidv4(), // 生成一个新的唯一ID
      ...createCatDto,
    };
    const response = {
      statusCode: HttpStatus.CREATED,
      message: 'Cat created successfully',
      data: cat,
    };
    res.status(HttpStatus.CREATED).json(response);
    // 调用 res.status().json() 方法时,它会设置响应的状态码并将数据以 JSON 格式发送给客户端。
    // 在这种情况下,不需要显式地使用 return 语句,因为框架会负责处理响应并结束请求。
    // return res.status(HttpStatus.CREATED).json(response);但是也可以这么写
  }

  //使用的是查询参数 id,那么可以继续使用 @Query() 装饰器来获取查询参数的值
  //比如请求路径是 http://localhost:3000/cats?id=18
  @Get('/query')
  findOneByQuery(@Query('id') id: string, @Res() res: Response) {
    const cat = `This action returns a #${id} cat by query`;
    res.status(HttpStatus.OK).json({
      statusCode: HttpStatus.OK,
      message: '处理成功',
      data: cat,
    });
  }

  //使用的是路径参数 id,那么你可以使用 @Param() 装饰器来获取查询参数的值
  // 比如请求路径是http://localhost:3000/cats/18
  @Get(':id')
  findOneByParam(@Param('id') id: string, @Res() res: Response) {
    const cat = `This action returns a #${id} cat by param`;
    return res.status(HttpStatus.OK).json({
      statusCode: HttpStatus.OK,
      message: '处理成功',
      data: cat,
    });
  }

  //1.路径参数的使用场景:

  // 标识资源:路径参数通常用于标识和定位特定的资源。它们可以用于表示资源的唯一标识符
  // 或标识符的一部分。例如,/cats/{id} 表示获取 ID 为 {id} 的猫咪资源。
  
  // 嵌套资源:当资源之间存在层级关系时,路径参数可以用于指定父资源和子资源之间的关系。
  // 例如,/users/{userId}/posts/{postId} 表示用户 ID 为 {userId} 的用户发布的帖子中
  // 的 ID 为 {postId} 的帖子。
  
  // 2. 查询参数的使用场景:

  // 过滤和排序:查询参数通常用于对资源进行筛选、过滤和排序。例如,/cats?color=black&size=small
  // 表示获取颜色为黑色且尺寸为小的猫咪资源。
  
  // 分页:查询参数可以用于分页结果集,允许客户端指定页码和每页的数量。
  // 例如,/cats?page=2&limit=10 表示获取第二页的猫咪资源,每页显示 10 条。
  
  // 参数化查询:查询参数可以用于传递参数化查询的参数。例如,/search?q=keyword 
  // 表示执行针对关键字 keyword 的搜索操作。
  
  // 总的来说,路径参数用于标识和定位资源,而查询参数用于对资源进行筛选、过滤、排序
  // 和参数化查询。路径参数通常出现在 URL 的路径中,而查询参数则出现在 URL 的查询字
  // 符串中。在设计 API 时,根据具体的需求和语义来选择使用路径参数或查询参数。

  @Get()
  findAll(@Res() res: Response) {
    // console.log('query', query);
    const data = 'hello World!!!';
    res.status(HttpStatus.OK).json({
      statusCode: HttpStatus.OK,
      message: '处理成功',
      data,
    });
  }

  @Put(':id')
  update(
    @Param('id') id: string,
    @Query('name') name: string,
    @Query('age') age: number,
    @Body() updateCatDto: UpdateCatDto,
    @Res() res: Response,
  ) {
    console.log('name', name);
    console.log('age', age);
    console.log('updateCatDto', updateCatDto);

    // 根据需要执行修改数据的操作

    const cat = `This action updates a #${id} cat`;
    return res.status(HttpStatus.OK).json({
      statusCode: HttpStatus.OK,
      message: '处理成功',
      data: cat,
    });
  }

  @Delete(':id')
  remove(@Param('id') id: string, @Res() res: Response) {
    const cat = `This action removes a #${id} cat`;
    return res.status(HttpStatus.OK).json({
      statusCode: HttpStatus.OK,
      message: '处理成功',
      data: cat,
    });
  }
}
5.4 接口测试:

启动服务:默认在 http://localhost:3000/ 运行

post接口测试:

get接口测试(带有查询参数):

get接口测试(带有路径参数):

get接口测试(不带参数,常用于返回所有数据):

put接口测试:

delete接口测试:

结语:到此,小编本次的分享就结束了,源码已经上传到github上了,需要的小伙伴可以自行下载测试,后续小编会继续发推文完善这个nest仓库的。最后,我再重申一遍,我只是一个初学nest的新手,如果哪里有错误烦请各位技术大牛纠正,小编将不胜感激。

源码地址:github.com/huangkaihao...

相关推荐
m0_7482561418 分钟前
前端 MYTED单篇TED词汇学习功能优化
前端·学习
小白学前端6661 小时前
React Router 深入指南:从入门到进阶
前端·react.js·react
web130933203982 小时前
前端下载后端文件流,文件可以下载,但是打不开,显示“文件已损坏”的问题分析与解决方案
前端
outstanding木槿2 小时前
react+antd的Table组件编辑单元格
前端·javascript·react.js·前端框架
好名字08213 小时前
前端取Content-Disposition中的filename字段与解码(vue)
前端·javascript·vue.js·前端框架
隐形喷火龙3 小时前
element ui--下拉根据拼音首字母过滤
前端·vue.js·ui
m0_748241123 小时前
Selenium之Web元素定位
前端·selenium·测试工具
风无雨3 小时前
react杂乱笔记(一)
前端·笔记·react.js
前端小魔女3 小时前
2024-我赚到自媒体第一桶金
前端·rust
鑫~阳3 小时前
快速建站(网站如何在自己的电脑里跑起来) 详细步骤 一
前端·内容管理系统cms