2024/11/03

NestJS 實現API版本控制

在現代API開發中,實現API版本控制是不可或缺的設計模式,特別是當應用逐步擴展且不斷迭代時,良好的版本管理至關重要。本文將介紹如何在NestJS中使用 VersioningType.URI 來實現API的版本控制,並深入分析兩種控制器的版本設定方式,幫助開發者根據實際需求選擇最佳方案。

Step 1: 設定全域前綴詞(setGlobalPrefix)

首先,設定全域前綴詞是必要的。務必先設定 setGlobalPrefix,再啟用版本控制,否則後續的版本控制將無法正確應用到API路徑。

// 設置全域的API前綴詞
const globalPrefix = 'api';
app.setGlobalPrefix(globalPrefix);

這行代碼會將所有API路徑統一設為/api開頭,例如/api/v1/test/echo。這樣可以讓API結構層次分明,並方便後續的維護和版本管理。

Step 2: 啟用版本控制(enableVersioning)


設置完前綴詞後,接下來啟用版本控制。這一步必須在前綴詞設置之後,才能讓版本號正確套用到API路徑。這裡選用 VersioningType.URI,讓版本資訊直接出現在URL中,讓客戶端可以通過不同的URL訪問不同的API版本。


import { VersioningType } from '@nestjs/common';

// 啟用版本控制,使用URI型別
app.enableVersioning({
  type: VersioningType.URI
});

此配置會讓NestJS根據URL中的版本號來自動匹配相應的控制器。例如,當請求/api/v1/...時,NestJS會將這個請求視為對第一版API的呼叫。

Step 3: 設定控制器的版本

在NestJS中,控制器的版本控制有兩種常用方式,各具優缺點:

方法 1: 在 @Controller 中設置版本

這種方式適合整個控制器都屬於同一個版本的情境。當控制器內的所有路由均屬於相同的API版本時,可以直接在 @Controller 裝飾器中設定 pathversion


import { Controller, Get } from '@nestjs/common';

// 在Controller中設定路徑和版本
@Controller({
  path: 'test',
  version: '1'
})
export class TestController {
  @Get('echo')
  async echo() {
    return { data: 'echo' };
  }
}

優點

  • 簡潔明瞭:一次設定即可讓控制器內的所有路由都自動套用該版本。
  • 方便管理:適合整個控制器共用同一版本的情境,不需要重複指定每個路由的版本號。

缺點

  • 缺乏靈活性:無法在控制器內針對單一路由支持多個版本。
  • 更新代價高:當其中某些路由需要單獨更新版本時,需要重構控制器或拆分路由,對於快速迭代來說可能不夠靈活。

方法 2: 使用 @Version 裝飾器針對單一路由設置版本

如果需要在同一控制器內支持多個版本,可以使用 @Version 裝飾器來針對特定路由指定版本。這種方式適合某些路由需要更新版本,而其他路由仍保留舊版本的情境。


import { Controller, Get, Version } from '@nestjs/common';

@Controller('test')
export class TestController {
  @Version('1')
  @Get('echo')
  async echo() {
    return { data: 'echo' };
  }
}

優點

  • 高度靈活:允許在同一控制器中針對不同路由設定不同版本,非常適合逐步更新API版本或同時支持多個版本的情境。
  • 便於過渡:在同一控制器中實現多版本共存,不影響整體API的穩定性,適合API過渡階段的需求。

缺點

  • 代碼可讀性降低:當控制器中的路由需要支持多個版本時,代碼的結構清晰度會下降,管理起來較為複雜。
  • 維護複雜性增加:由於每個路由可以單獨設定版本,維護時需要仔細檢查每個路由的版本設定,增加了出錯的風險。

Step 4: 模組化 API 路由

隨著應用程式的增長,將不同版本的API分離到獨立的模組中可以提升維護效率,讓架構更具擴展性。以下範例展示了如何建立 RoutesModule 來統籌不同版本的API模組,並引入第一版本的模組 V1Module


import { Module } from '@nestjs/common';
import { V1Module } from '../v1/v1.module';

@Module({
  imports: [
    V1Module, // 引入V1版本模組
  ],
})
export class RoutesModule {}

V1Module 中定義該版本的控制器:


import { Module } from '@nestjs/common';
import { TestController } from './test.controller';

@Module({
  controllers: [TestController], // 註冊V1版本控制器
})
export class V1Module {}

這樣的模組結構便於未來新增API版本,每新增一個版本時,只需創建新的模組並註冊相應控制器,而不會影響現有的版本模組。

小結

在NestJS中進行API版本控制的最佳實踐流程是:先設定全域前綴詞,再啟用版本控制,以確保API前綴和版本控制都被正確應用到路徑中。可以選擇在 @Controller 中設置版本以統一管理,也可以透過 @Version 裝飾器指定單一路由的版本,靈活應對多版本需求。

選擇 @Controller 的版本設定:適合全控制器共用一個版本的情境,實現簡單,代碼結構清晰;但對於單路由版本更新不夠靈活。

選擇 @Version 的路由版本設定:適合逐步過渡到新版本或部分路由支持多版本的情境,靈活度高;但維護時更為複雜,需要細緻的版本管理。

選擇適合的方式可以讓API更加靈活、易於維護,並更適應實際需求的變化。


參考資料:

Versioning