banner
cos

cos

愿热情永存,愿热爱不灭,愿生活无憾
github
tg_channel
bilibili

NestJS 學習之優秀專案分析與最佳實踐

前言#

進入 NestJS 的世界可能會讓你感到不知所措,尤其是當你面對眾多的模組和概念時。本文不僅會深入分析優秀的 NestJS 項目,介紹常用的 Nest 內置模組,還會解鎖一些 NestJS 的高級特性和最佳實踐,來幫助你更好地理解和應用這個強大的 Node.js 框架。無論你是一個初學者還是有經驗的開發者,這篇文章都將為你提供寶貴的見解和實用的技巧,讓你能夠更加了解 NestJS。

我將從 GitHub 上的 Awesome NestJS 列表中選取優秀項目進行分析,看它們如何使用 NestJS 的各種功能和模組。 此外,我還將詳細介紹一些常用的 Nest 內置模組,如 @nestjs/core,並通過代碼示例展示它們的應用場景。

本文還包括一些重要的後端常用術語解釋,以幫助你更全面地理解這個框架。

本文不會直接告訴你如何從零開始搭建一個 NestJS 項目,因為這樣的教程和文章網上已經有很多。 相反,本文的主要目的是通過深入分析和解讀,讓你在實際應用中能更加得心應手。當你遇到某個模組或功能不知如何使用時,這篇文章將作為你的參考和靈感來源。

通過這樣的角度和方法,我希望能幫助你不僅僅是 “會用”,而是 “懂得用” NestJS,從而更加自信和高效地進行後端開發。

讓我們一起深入 NestJS 的世界,探索它的無限可能性吧!

整體架構 & 名詞解釋#

在深入 NestJS 的各種模組和功能之前,了解常見優秀項目的整體架構和相關名詞是非常重要的。這不僅有助於你更好地理解框架的工作原理,還能讓你在開發過程中做出更加明智的決策。

目錄結構#

prisam // 資料庫相關
src
├─ auth // 授權登錄模組
   ├─ auth.controller.ts
   ├─ auth.guard.ts // 守衛 
   ├─ auth.interface.ts // 存放局部的該模組的類型聲明
   ├─ auth.module.ts
   ├─ auth.service.ts
   ├─ dto
   │   ├─ sign-in.dto.ts
   ├─ entities
   │   └─ refresh-token.entity.ts
├─ common // 全局通用模組
|   ├─ configs // 全局配置 
|   ├─ constants // 定義一些常量
|   ├─ decorators // 全局裝飾器
|   ├─ filters // 全局過濾器
|   ├─ interceptors // 全局攔截器
|   ├─ interfaces // 全局類型聲明
|   ├─ services // 全局公共服務
|   ├─ * // 其他
├─ utils // 工具函數, 儘量存放純函數
├─ app.*.ts // app 模組, 其他 module 需要引用到 app module
├─ main.ts // 應用入口

以一個用戶授權模組為例,通常能看到這些文件,而它們的用途如下:

  • *.module.ts : 通常是模組文件,用於組織和管理控制器、服務、守衛等。它是 Nest.js 應用程序的基礎單元
  • *.service.ts : Service 層通常用於處理模組的業務邏輯。它們通常被注入到控制器(controller)中,並可以訪問資料庫、執行計算等。
  • *.controller.ts : 控制器文件用於處理 HTTP 請求和響應。它們通常依賴於 Service 來執行業務邏輯。
  • *.guard.ts : 守衛文件用於實現路由保護,例如身份驗證和授權。
  • *.interface.ts : 接口文件用於定義局部用到的類型和數據結構,以確保代碼的健壯性。(ts 聲明等)
  • *.dto.ts : 數據傳輸對象(DTO)用於驗證客戶端發送的數據。
  • *.entity.ts : 實體文件用於定義資料庫模型。

其中一些名詞的簡單解釋如下:

  • DTO(Data Transfer Object): 數據傳輸對象,用於在對象和 API 之間傳輸數據。
  • Guard: 守衛,用於實現權限控制和訪問驗證。
  • Module: 模組,NestJS 的基本組織單位,用於組織和管理控制器、服務等。
  • Service: 服務,包含主要的業務邏輯,通常被注入到控制器中。
  • Entity: 實體,用於定義資料庫模型,通常與 ORM(對象關係映射)一起使用。
  • Interceptor: 拦截器在 NestJS 中是一個用 @Injectable() 裝飾器註釋的類,並實現 NestInterceptor 接口。拦截器用於在函數執行之前或之後執行一些操作,例如日誌記錄、異常處理、數據轉換等。
  • Reflector: Reflector 主要用於元數據的反射和操作。在拦截器中,Reflector 可以用於獲取方法或類上設置的自定義元數據,從而允許更靈活的操作。

通過以上的目錄結構和名詞解釋,我希望能為你提供一個清晰的視角,以更全面地理解 NestJS 的架構和設計理念。接下來,我們將深入探討這些概念,並通過實際的代碼示例來展示它們是如何在 NestJS 項目中應用的。

Module#

  1. 根模組:每個 Nest.js 應用程序都有一個根模組,它是 Nest 用於構建應用程序圖 (application graph)的起點。這個圖用於解析模組與提供者(Providers)之間的關係和依賴。
  2. 組織組件:模組是組織和管理組件(如控制器、服務等)的有效方式。通過模組,你可以將密切相關的功能組合在一起。
  3. 多模組架構:對於大型應用程序,通常會採用多模組架構。每個模組都封裝了一組特定的、密切相關的功能。
// 引入Nest.js核心模組
import { Module } from '@nestjs/common';
// 引入其他相關組件
import { AppController } from './app.controller';
import { AppService } from './app.service';

// 使用@Module裝飾器定義模組
@Module({
  // 導入其他模組
  imports: [],
  // 聲明該模組的控制器
  controllers: [AppController],
  // 聲明該模組的提供者(通常是服務)
  providers: [AppService],
})
export class AppModule {}

推薦閱讀#

  1. Modules | NestJS - A progressive Node.js framework
  2. 深入了解 Nest 的模組 Module - 掘金

Service 層(服務層)#

在軟體架構中,通常會有幾個不同的層來組織代碼和功能。這些層有助於實現關注點分離(Separation of Concerns),使得代碼更易於維護和擴展。在本例中,我們主要關注以下幾個層:Service 層和 Controller 層,至於 DAO 層:

無論是 nest 還是 egg,官方 demo 裡都沒有明確提到 dao 層,直接在 service 層操作資料庫了。這對於簡單的業務邏輯沒問題,如果業務邏輯變得複雜,service 層的維護將會變得非常困難。業務一開始一般都很簡單,它一定會向著複雜的方向演化,如果從長遠考慮,一開始就應該保留 dao。

Service 層主要負責業務邏輯的實現。這一層通常會與資料庫進行交互,執行 CRUD(創建、讀取、更新、刪除)操作,以及執行其他與業務邏輯相關的任務。

例如,一個名為 UserService 的服務可能有一個 registerUser 方法,該方法接收一個 LoginUserDto 對象,驗證數據,並將新用戶添加到資料庫中。

import { Injectable } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';
import { LoginUserDto } from './dto/LoginUserDto';

@Injectable()
export class AuthService {
  private prisma: PrismaClient;

  constructor() {
    this.prisma = new PrismaClient();
  }

  async registerUser(dto: LoginUserDto): Promise<void> {
    await this.prisma.user.create({
      data: {
        userName: dto.userName,
        password: dto.password,
      },
    });
  }
}

推薦閱讀#

  1. NestJS - Services
  2. nest 後端開發實戰(二)—— 分層 - 知乎
  3. 淺談 NestJS 設計思想(分層、IOC、AOP) - 掘金

Controller 層(控制器層)#

Controller 層主要負責處理來自客戶端的請求和發送響應。控制器會使用 Service 層提供的方法來執行業務邏輯,並將結果返回給客戶端。

例如,一個名為 UserController 的控制器可能有一個 register 方法,該方法接收客戶端發送的 HTTP POST 請求和 LoginUserDto 數據。

import { Controller, Post, Body } from '@nestjs/common';
import { UserService } from './user.service';
import { LoginUserDto } from './dto/LoginUserDto';

@Controller('user')
export class UserController {
  constructor(private readonly userService: UserService) {}

  @Post('register')
  async register(@Body() userDto: LoginUserDto) {
    return await this.userService.registerUser(userDto);
  }
}

推薦閱讀#

  1. Controllers | NestJS
  2. nest.js-Controller 基礎用法 - 掘金

DTO(Data Transfer Object)#

用 po 和 dto 來描述實體及其周邊。po 是持久化對象和資料庫的表結構一一對應;dto 數據傳輸對象則很靈活,可以在豐富的場景描述入參或返回值。下面是個 user 實體的例子:

與 Service 層和 Controller 層的關係#

  • 在 Controller 層,DTO 用於驗證來自客戶端的請求數據。當客戶端發送一個請求時,Nest.js 會使用 DTO 來驗證請求體中的數據是否符合預期的格式和類型。
  • 在 Service 層,DTO 用於執行業務邏輯。

這樣,DTO 成為了 Controller 層和 Service 層之間的橋樑,使得數據在這兩個層之間能夠流動和轉換,同時保證了類型安全和數據驗證。

在這個例子中,LoginUserDto 是一個 DTO,它定義了用戶註冊時需要提交的數據格式。這個 DTO 在 Controller 層用於接收客戶端的數據,並在 Service 層用於執行業務邏輯。

// module/dto/LoginUserDto.ts 
import { IsString, IsNotEmpty } from 'class-validator';

export class LoginUserDto {
  @IsString()
  @IsNotEmpty()
  userName: string;

  @IsString()
  @IsNotEmpty()
  password: string;
}

以上代碼定義了用戶註冊時需要提交的數據格式。使用 class-validator 庫來進行數據驗證。

  • 屬性解釋

    • userName: 用戶名,必須是字符串類型。
    • password: 密碼,必須是字符串類型。
  • 裝飾器解釋

    • @IsString(): 確保字段是字符串類型。
    • @IsOptional(): 表示字段是可選的。

更多解釋使用詳見 https://github.com/typestack/class-validator#usage

推薦閱讀#

  1. 學習 Nest.js(五):使用管道、DTO 驗證入參 - 知乎
  2. NestJS 官方文檔:DTO 和驗證

Entity(實體)#

在 NestJS 或其他 TypeScript 框架中,.entity.ts 文件用於定義資料庫模型。這些模型通常與資料庫表一一對應,並用於描述表的結構和關係。實體類通常使用裝飾器(decorators)來標註字段和其類型,以便 ORM 工具能夠正確地與資料庫交互。。

例如,一個名為 UserEntity 的實體可能如下所示:

import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';

@Entity('users')
export class UserEntity {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ length: 500 })
  name: string;

  @Column('text')
  description: string;
}

在這個例子中,UserEntity 類與資料庫中的 users 表對應。它有三個字段:idnamedescription,這些字段的類型和長度也通過裝飾器進行了標註。

若是使用 Prisma ORM,則實體文件一般為單純的類型定義如

export class GameInfo {
  id: number;
  name: string | null;
  description: string | null;
}

因為 prsima 的定義在 schema.prisma 中。

示例代碼#

以下是一個名為 RefreshTokenEntity 的實體類示例,該實體用於存儲用戶的錢包地址和 JWT 訪問令牌。

import { Entity, Column, PrimaryColumn } from 'typeorm';
import { IsString } from 'class-validator';
import { Transform } from 'class-transformer';

@Entity('refresh_tokens')
export class RefreshTokenEntity {
  /**
   * 用戶錢包地址
   */
  @PrimaryColumn()
  @IsString()
  @Transform(({ value }) => getAddress(value))
  public address: string;

  /**
   * Jwt Token
   */
  @Column('text')
  public accessToken: string;
}

在這個例子中,RefreshTokenEntity 類與資料庫中的 refresh_tokens 表對應。它有兩個字段:addressaccessTokenaddress 字段還使用了 class-validatorclass-transformer 庫的裝飾器進行了額外的驗證和轉換。

這樣,你就可以在 Service 層或 DAO 層使用這個實體類進行資料庫操作。

推薦閱讀#

  1. TypeORM - Entity
  2. NestJS - TypeORM

Guard(守衛)#

在 NestJS 和其他一些後端框架中,Guard(守衛)是一種特殊類型的服務,用於實現路由保護。它們通常用於身份驗證授權,以確保只有具有適當權限的用戶才能訪問特定的路由或執行特定的操作。

例如,下面是一個名為 AuthGuard 的簡單守衛,該守衛使用 JWT(JSON Web Token)進行身份驗證:

import { CanActivate, ExecutionContext, Injectable, UnauthorizedException } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { Reflector } from '@nestjs/core';
import { ConfigService } from '@nestjs/config';

@Injectable()
export class AuthGuard implements CanActivate {
  constructor(
    private jwtService: JwtService,
    private configService: ConfigService,
    private reflector: Reflector
  ) {}

  async canActivate(context: ExecutionContext): Promise<boolean> {
    const request = context.switchToHttp().getRequest();
    const token = request.headers['authorization']?.split(' ')[1];

    if (!token) {
      throw new UnauthorizedException('Token is missing');
    }

    try {
      const decoded = this.jwtService.verify(token);
      request.user = decoded;
      return true;
    } catch (error) {
      throw new UnauthorizedException('Invalid token');
    }
  }
}

在這個例子中,AuthGuard 實現了 CanActivate 接口,並定義了一個 canActivate 方法。這個方法會檢查請求頭中是否包含有效的 JWT。如果包含,該請求將被允許繼續;否則,將拋出 UnauthorizedException

推薦閱讀#

  1. NestJS - Guards
  2. NestJS 守衛(Guards)詳解 - 掘金
  3. NestJS 實戰:使用 Guards 進行權限控制 - 知乎

通過使用 Service 層和 Guard 層,你可以更有效地組織你的代碼,使其更加模組化和可維護。同時,這也有助於實現更強大和靈活的業務邏輯和安全控制。

Interceptor(攔截器)#

在 NestJS 中,攔截器(Interceptor) 是一個用 @Injectable() 裝飾器註釋的類,並實現 NestInterceptor 接口。攔截器通常用於在函數執行之前或之後執行一些操作。攔截器可以用於多種用途,例如日誌記錄、異常處理、數據轉換等。

一個簡單的 LoggingInterceptor :

import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';

@Injectable()
export class LoggingInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    console.log('Before...');

    const now = Date.now();
    return next
      .handle()
      .pipe(
        tap(() => console.log(`After... ${Date.now() - now}ms`)),
      );
  }
} 

因為 handle() 返回 RxJS Observable ,因此我們可以使用多種運算符來操作流。在上面的示例中,我們使用了 tap() 運算符,它在可觀察流正常或異常終止時調用我們的匿名日誌記錄函數,但不會以其他方式干擾響應週期。

轉換響應數據攔截器#

一個簡單的轉換響應數據攔截器示例如下,該攔截器可以根據需要返回原始數據或包裝後的數據。

定義響應接口和元數據鍵#

首先,我們定義一個響應接口IResponse和一個元數據鍵IS_RAW_DATA_KEY

import { SetMetadata } from '@nestjs/common';
  
export interface IResponse<T> {
  code: number;
  message: string;
  data: T;
}

export const IS_RAW_DATA_KEY = 'is-raw-data';

/**
 * 控制返回數據是否通過 Response 包裝
 * @constructor
 */
export const RawData = () => SetMetadata(IS_RAW_DATA_KEY, true);
  • IResponse<T>: 用於包裝響應數據的接口。
  • IS_RAW_DATA_KEY: 用於標記是否返回原始數據的元數據鍵。
  • RawData(): 一個裝飾器,用於設置元數據鍵。

看不懂元數據?別急,接著看。

實現攔截器#

接下來,我們實現轉換響應數據的攔截器。

// transform.interceptor.ts
import { IResponse, IS_RAW_DATA_KEY } from '@/common';
import { map, Observable } from 'rxjs';
import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common';
import { Reflector } from '@nestjs/core';

/**
 * 處理響應數據轉化
 */
@Injectable()
export class TransformInterceptor<T> implements NestInterceptor<T, IResponse<T> | T> {
  constructor(private reflector: Reflector) {}

  intercept(context: ExecutionContext, next: CallHandler<T>): Observable<IResponse<T> | T> {
    const isRawData = this.reflector.getAllAndOverride<boolean>(IS_RAW_DATA_KEY, [context.getHandler(), context.getClass()]);
    return next.handle().pipe(map((data) => (isRawData ? data : { code: 200, message: 'success', data })));
  }
}
  • TransformInterceptor: 攔截器的主體。
  • isRawData: 用於檢查是否需要返回原始數據。
  • next.handle().pipe(...): 根據isRawData的值來決定返回原始數據還是包裝後的數據。
在 AppModule 中引用攔截器#

最後,在 AppModule 中添加攔截器。

import { TransformInterceptor } from '@/common';
import { Module } from '@nestjs/common';
import { APP_INTERCEPTOR } from '@nestjs/core';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [
    // others...
  ],
  controllers: [AppController],
  providers: [
    // others...
    {
      provide: APP_INTERCEPTOR,
      useClass: TransformInterceptor,
    },
    AppService,
  ],
})
export class AppModule {}
使用 RawData 裝飾器#

現在,你可以在 Controller 中使用@RawData()裝飾器來控制是否返回原始的響應數據。

@Controller('someResource')
export class SomeController {
  constructor(private someService: SomeService) {}

  @RawData()
  @Get(':someParam')
  someMethod(@Param('someParam') someParam: number): Promise<SomeEntity> {
    // 實現細節
  }
}

通過這種方式,你可以靈活地控制響應數據的格式。

Nest.js,很神奇吧。

推薦閱讀#

  1. NestJS 官方文檔:攔截器
  2. NestJS interceptors: Guide and use cases - LogRocket Blog

這樣,你就可以更好地理解 Interceptor 層在 NestJS 中的作用和實現方式。希望這能幫助你更深入地了解 NestJS 的架構和最佳實踐。

Reflector(反射器)#

在 NestJS 中,Reflector 是一個用於檢索元數據的實用工具類。它通常用於自定義裝飾器和攔截器中,以獲取關於類、方法或屬性的額外信息。這些信息可能是通過裝飾器在編譯時添加的

在上面的攔截器例子中,Reflector 被用於獲取與當前執行上下文(ExecutionContext)相關的元數據。這裡,它用於檢查是否應返回原始數據或應將數據封裝在一個響應對象中。

const isRawData = this.reflector.getAllAndOverride<boolean>(IS_RAW_DATA_KEY, [context.getHandler(), context.getClass()]);

這行代碼使用 getAllAndOverride 方法從當前的處理程序或類中獲取 IS_RAW_DATA_KEY 的元數據。然後,這個元數據用於決定如何轉換響應數據。

使用場景#

  1. 自定義裝飾器:如果你有一個自定義裝飾器,你可能需要使用 Reflector 來讀取與該裝飾器相關的元數據。
  2. 權限控制:在攔截器或守衛中,你可以使用 Reflector 來獲取關於用戶角色或權限的元數據,以實現更細粒度的控制。
  3. 響應轉換:如上面的例子所示,你可以使用 Reflector 來決定如何格式化或轉換出口數據。

示例代碼#

import { Reflector } from '@nestjs/core';

@Injectable()
export class RolesGuard implements CanActivate {
  constructor(private reflector: Reflector) {}

  canActivate(context: ExecutionContext): boolean {
    const roles = this.reflector.get<string[]>('roles', context.getHandler());
    // ... 權限檢查邏輯
  }
}

推薦閱讀#

  1. NestJS - Reflector
  2. NestJS - Custom Decorators
  3. NestJS 深入理解 Reflector 的使用場景

這樣,Reflector 就成為了在 NestJS 中實現高度可配置和動態行為的關鍵工具。

常用 Nest 內置模組#

這是扒拉各種 nest 項目的 package.json 總結得出的模組簡介:

@nestjs/core#

  • NPM: @nestjs/core
  • 文檔: NestJS Core Module
  • 簡介: 這是 NestJS 框架的核心模組,提供了框架的基礎構建塊和核心功能
  • 使用場景: 用於構建和初始化 NestJS 應用,幾乎所有 NestJS 項目都會用到。
  • 代碼示例:
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(3000);
}
bootstrap();

``

@nestjs/jwt#

  • NPM: @nestjs/jwt
  • 文檔: NestJS JWT Module
  • 簡介: 這個模組提供了 JWT(JSON Web Tokens)的支持,用於在 NestJS 應用中實現身份驗證和授權
  • 使用場景: 身份驗證和授權,通常用於保護路由和資源。
  • 代碼示例:
import { JwtService } from '@nestjs/jwt';

@Injectable()
export class AuthService {
  constructor(private readonly jwtService: JwtService) {}

  async generateToken(user: User) {
    return this.jwtService.sign({ user });
  }
}

@nestjs/config#

  • NPM: @nestjs/config
  • 文檔: NestJS Config Module
  • 簡介: 這個模組用於管理 NestJS 應用的配置信息。它支持環境變量、類型轉換等。
  • 使用場景: 用於管理應用的配置信息,如資料庫連接字符串、API 密鑰等。
  • 代碼示例:
import { ConfigService } from '@nestjs/config';

@Injectable()
export class AppService {
  constructor(private configService: ConfigService) {}

  getDatabaseUrl(): string {
    return this.configService.get<string>('DATABASE_URL');
  }
}

@nestjs/common#

  • NPM: @nestjs/common
  • 文檔: NestJS Common Module
  • 簡介: 這是 NestJS 的一個通用模組,提供了一系列常用的裝飾器、助手函數和其他工具。如 Injectable, Module, BadRequestException, Body, Controller, Get, Param, Post, Query
  • 使用場景: 在 Controller 層、Service 層、Module 中都會用到,用於定義路由、依賴注入等。
  • 代碼示例:
import { Controller, Get } from '@nestjs/common';

@Controller('hello')
export class HelloController {
  @Get()
  sayHello(): string {
    return 'Hello World!';
  }
}

@nestjs/axios#

  • NPM: @nestjs/axios
  • 文檔: NestJS Axios Module
  • 簡介: 這個模組為 NestJS 提供了 Axios HTTP 客戶端的封裝,使得在 NestJS 應用中進行 HTTP 請求更加方便。 如 HttpService, HttpModule
  • 使用場景: 在 Service 層進行 HTTP 請求,如調用第三方 API。
  • 代碼示例:
import { HttpService } from '@nestjs/axios';

@Injectable()
export class ApiService {
  constructor(private httpService: HttpService) {}

  async fetchData(url: string) {
    const response = await this.httpService.get(url).toPromise();
    return response.data;
  }
}

實際項目一般會自行重寫 http Service 請求添加統一的日誌等,如下:

import { HttpService } from '@nestjs/axios';
import { catchError, Observable, tap } from 'rxjs';
import { AxiosError, AxiosRequestConfig, AxiosResponse } from 'axios';
import { BadRequestException, Injectable, Logger } from '@nestjs/common';

@Injectable()
export class HttpClientService {
  constructor(private httpService: HttpService) {}

  private logger: Logger = new Logger(HttpClientService.name);
  
  /**
   * 重寫 http Service GET 請求, 打印 Request 和 Response
   * @param url
   * @param config
   */
  get<T = any>(url: string, config?: AxiosRequestConfig): Observable<AxiosResponse<T, any>> {
    // 打印發送請求的信息
    this.logger.log(`GET ${url}`);
    return this.httpService.get<T>(url, config).pipe(
      // 在不改變 Observable 流的情況下打印收到的響應
      tap((response) => this.logger.log(`Response ${url} ${JSON.stringify(response.data)}`)),
      // 捕獲錯誤,並打印錯誤信息
      catchError((error: AxiosError) => {
        const errorData = JSON.stringify(error.response?.data);
        this.logger.error(`GET Error ${url} ${errorData}`);
        throw new BadRequestException([errorData]);
      }),
    );
  }
}

@nestjs/bull#

  • NPM: @nestjs/bull
  • 文檔: NestJS Bull Module
  • 簡介: 這個模組提供了 Bull 隊列庫的封裝,用於在 NestJS 應用中處理後台作業和消息隊列
  • 使用場景: 後台任務處理,如發送郵件、數據處理等。
  • 代碼示例:
import { Processor, Process } from '@nestjs/bull';
import { Job } from 'bull';

@Processor('audio')
export class AudioProcessor {
  @Process('transcode')
  async transcode(job: Job<number>) {
    // Your logic here
  }
}

@nestjs/cache-manager#

  • NPM: @nestjs/cache-manager
  • 文檔: NestJS Caching
  • 簡介: 這個模組提供了緩存管理功能,支持多種緩存存儲方式,如內存、Redis 等
  • 使用場景: 數據緩存,如 API 響應資料庫查詢結果會話緩存等。
  • 代碼示例: 在這個示例中,我們使用了 CacheModule 來註冊緩存,並使用 CacheInterceptor 攔截器來自動處理緩存邏輯。這樣,當多次訪問 findAll 方法時,結果會被緩存,從而提高響應速度。
import { CacheModule, CacheInterceptor, Controller, UseInterceptors } from '@nestjs/common';
import { CachingConfigService } from './caching-config.service';

@Module({
  imports: [
    CacheModule.registerAsync({
      useClass: CachingConfigService,
    }),
  ],
})
export class AppModule {}

@Controller('posts')
export class PostsController {
  @UseInterceptors(CacheInterceptor)
  @Get()
  findAll() {
    // Your logic here
  }
}

@nestjs/mongoose#

  • NPM: @nestjs/mongoose
  • 文檔: NestJS Mongoose Module
  • 簡介: 這個模組提供了 Mongoose ODM(對象文檔映射)的封裝,用於在 NestJS 應用中與 MongoDB 資料庫進行交互。
  • 使用場景: 資料庫操作,特別是與 MongoDB 資料庫的交互。
  • 代碼示例:
import { Schema, Prop, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';

@Schema()
export class Cat extends Document {
  @Prop()
  name: string;
}

export const CatSchema = SchemaFactory.createForClass(Cat);

@nestjs/platform-express#

  • NPM: @nestjs/platform-express
  • 文檔: NestJS Overview
  • 簡介: 這個模組是 NestJS 框架的 Express 適配器,用於在 NestJS 應用中使用 Express.js。
  • 使用場景: 用到其中的 FileInterceptor 處理文件上傳
  • 代碼示例: 在這個示例中,我們使用了 @nestjs/platform-express 提供的 FileInterceptor 來處理文件上傳。這實際上是對 Express 的 multer 中間件的封裝。
import { Controller, Post, UploadedFile, UseInterceptors } from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { diskStorage } from 'multer';

@Controller('upload')
export class UploadController {
  @Post()
  @UseInterceptors(FileInterceptor('file', {
    storage: diskStorage({
      destination: './uploads',
      filename: (req, file, cb) => {
        cb(null, `${Date.now()}-${file.originalname}`);
      },
    }),
  }))
  uploadFile(@UploadedFile() file) {
    return { url: `./uploads/${file.filename}` };
  }
}

@nestjs/schedule#

  • NPM: @nestjs/schedule
  • 文檔: NestJS Schedule Module
  • 簡介: 這個模組提供了任務調度功能,用於在 NestJS 應用中執行定時任務。
  • 使用場景: 定時任務,如每日數據備份、定時推送等。
  • 代碼示例:
import { Cron, CronExpression } from '@nestjs/schedule';

@Injectable()
export class TasksService {
  @Cron(CronExpression.EVERY_5_SECONDS)
  handleCron() {
    // Your logic here
  }
}

@nestjs/swagger#

  • NPM: @nestjs/swagger
  • 文檔: NestJS Swagger Module
  • 簡介: 這個模組用於生成和維護 API 文檔,基於 Swagger。
  • 使用場景: 自動生成 API 文檔。
  • 代碼示例:
import { ApiProperty } from '@nestjs/swagger';

export class CreateUserDto {
  @ApiProperty()
  username: string;

  @ApiProperty()
  password: string;
}

@nestjs/throttler#

  • NPM: @nestjs/throttler
  • 文檔: NestJS Throttler
  • 簡介: 這個模組提供了請求限制(Rate Limiting)功能,用於防止 API 被濫用。 有 ThrottlerGuard, SkipThrottle
  • 使用場景: 防止 API 濫用,如限制每分鐘請求次數。
  • 代碼示例:
import { ThrottlerGuard } from '@nestjs/throttler';

@Injectable()
export class AppGuard extends ThrottlerGuard {
  // Your logic here
}

其他包#

class-validator#

import { IsEmail, IsNotEmpty } from 'class-validator';

export class CreateUserDto {
  @IsNotEmpty()
  name: string;

  @IsEmail()
  email: string;
}

class-transformer#

  • NPM: class-transformer
  • 文檔: class-transformer GitHub
  • 簡介: 用於對象與類實例之間的轉換,通常與 class-validator 配合使用。
  • 使用場景: 對象轉換和序列化。
  • 代碼示例:
import { plainToClass } from 'class-transformer';

const user = plainToClass(User, {
  name: 'John Doe',
  email: '[email protected]'
});

cache-manager#

  • NPM: cache-manager
  • 文檔: cache-manager GitHub
  • 簡介: 一個靈活、可擴展的緩存模組,支持多種存儲方式。
  • 使用場景: 數據緩存,如 API 響應、資料庫查詢結果等。
  • 代碼示例:
import * as cacheManager from 'cache-manager';

const memoryCache = cacheManager.caching({ store: 'memory', max: 100, ttl: 10 });

async function getUser(id: string) {
  const cachedUser = await memoryCache.get(id);
  if (cachedUser) {
    return cachedUser;
  }

  const user = await fetchUserFromDb(id);
  await memoryCache.set(id, user);
  return user;
}

hashids#

import Hashids from 'hashids';

const hashids = new Hashids();
const id = hashids.encode(12345); // 輸出一個短的唯一字符串

ioredis#

  • NPM: ioredis
  • 文檔: ioredis GitHub
  • 簡介: 一個健全、高效的 Redis 客戶端。
  • 使用場景: Redis 資料庫操作、緩存管理等。
  • 代碼示例:
import Redis from 'ioredis';

const redis = new Redis();
redis.set('key', 'value');

mongoose#

  • NPM: mongoose
  • 文檔: Mongoose Documentation
  • 簡介: 用於 MongoDB 和 Node.js 的對象數據模型(ODM)庫。
  • 使用場景: MongoDB 資料庫操作、數據模型定義等。
  • 代碼示例:
import mongoose from 'mongoose';

const userSchema = new mongoose.Schema({
  username: String,
  password: String,
});

const User = mongoose.model('User', userSchema);

nestgram#

  • NPM: nestgram
  • 文檔: About Nestgram - Nestgram
  • 簡介: 一個用於 NestJS 的 Telegram 機器人庫。
  • 使用場景: 在 NestJS 應用中集成 Telegram 機器人。
  • 代碼示例:
import { Nestgram } from 'nestgram';

const nestgram = new Nestgram({ token: 'YOUR_BOT_TOKEN' });
nestgram.on('message', (msg) => {
  // 處理消息
});

nestjs-throttler-storage-redis#

import { ThrottlerModule } from '@nestjs/throttler';
import { RedisThrottlerStorage } from 'nestjs-throttler-storage-redis';

@Module({
  imports: [
    ThrottlerModule.forRoot({
      storage: new RedisThrottlerStorage(),
    }),
  ],
})
export class AppModule {}

ramda#

  • NPM: ramda
  • 文檔: Ramda Documentation
  • 簡介: 一個實用的函數式編程庫。
  • 使用場景: 數據轉換、函數組合等。
  • 代碼示例:
import * as R from 'ramda';

const addOne = R.add(1);
const result = addOne(2); // 輸出 3

redis#

  • NPM: redis
  • 文檔: redis GitHub
  • 簡介: Node.js 的 Redis 客戶端。
  • 使用場景: 在 Node.js 應用中與 Redis 資料庫進行交互。
  • 代碼示例:
import * as redis from 'redis';
const client = redis.createClient();

client.set('key', 'value');
client.get('key', (err, reply) => {
  console.log(reply); // 輸出 'value'
});

reflect-metadata#

import 'reflect-metadata';

@Reflect.metadata('role', 'admin')
class User {
  constructor(public name: string) {}
}

const metadata = Reflect.getMetadata('role', User);
console.log(metadata); // 輸出 'admin'

rxjs#

  • NPM: rxjs
  • 文檔: RxJS Documentation
  • 簡介: 用於使用可觀察對象進行響應式編程的庫。
  • 使用場景: 異步編程、事件處理等。
  • 代碼示例:
import { of } from 'rxjs';
import { map } from 'rxjs/operators';

const source$ = of(1, 2, 3);
const result$ = source$.pipe(map(x => x * 2));

result$.subscribe(x => console.log(x)); // 輸出 2, 4, 6
載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。