在持续迭代的现代应用开发中,版本控制是无法绕开的问题。任何对现有接口的修改,如果没有一个有效的版本控制机制,都可能导致应用全局范围的影响。那么,如何实现一个清晰且高效的接口版本控制呢?
多版本控制策略希望在设计之初就考虑到,以确保应用具备良好的灵活性和可扩展性。而 NestJS 的强大功能,就带给我们实现多版本控制的可能。
NestJS 是一个强大且灵活的 Node.js 框架,它提供的模块化架构可以让我们为每个版本的代码创建特定的模块。这样,一旦对某个版本的代码需要修改,修改的内容就会被严格地限制在这个模块中,最大限度地减少对其他版本产生影响。
本文将带你了解使用 NestsJS 如何实现接口多版本控制。
在 NestJS 中,多版本控制可支持三种类型:
URI Versioning(URI版本控制)
这种类型的版本控制将版本信息放在请求的 URI 中。例如 https://example.com/v1/route
和 https://example.com/v2/route
。
Header Versioning(标头版本控制)
标头版本控制将使用自定义的、用户指定的请求标头来指定版本信息。
Media Type Versioning(媒体类型版本控制)
媒体类型版本控制使用请求的 Accept
标头来指定版本信息。
接下来,我们将详细介绍这三种类型的版本控制。
URI 版本控制使用在请求的 URI 中传递的版本信息,例如 https://example.com/v1/route
和 https://example.com/v2/route
。注意使用 URI 版本控制,版本信息将自动添加到 URI 中全局路径前缀(如果存在)之后,任何控制器或路由路径之前。
为了要启用 URI 版本控制,你需要在 main.ts
文件中这样配置:
shellimport { NestFactory } from '@nestjs/core'; import { VersioningType } from '@nestjs/common'; import { AppModule } from './app.module'; async function bootstrap() { const app = await NestFactory.create(AppModule); // or "app.enableVersioning()" app.enableVersioning({ type: VersioningType.URI, }); await app.listen(3000); } bootstrap();
默认情况下,URI 中的版本将自动以 v
为前缀,但是可以通过将 prefix
键设置为你想要的前缀来配置前缀值,如果你希望禁用它,则可以设置为 false
。
标头版本控制使用自定义的、用户指定的请求标头来指定版本信息。例如,你可以编写一个包含了特定版本信息的 HTTP 请求:
shellGET /cats HTTP/1.1 Host: example.com Accept: application/json Custom-Header: 2
启用标头版本控制,你需要在 main.ts
文件中这样配置:
typescriptimport { NestFactory } from '@nestjs/core'; import { VersioningType } from '@nestjs/common'; import { AppModule } from './app.module'; async function bootstrap() { const app = await NestFactory.create(AppModule); app.enableVersioning({ type: VersioningType.HEADER, header: 'Custom-Header', }); await app.listen(3000); } bootstrap();
header
属性就是包含请求版本的标头的名称。
媒体类型版本控制使用 Accept
请求的标头来指定版本信息。在 Accept
标头中,版本将与媒体类型用分号 ;
分隔。然后它应该包含一个键值对,表示用于请求的版本,例如 Accept: application/json;v=2
。在确定要配置为包含键和分隔符的版本时,它们的键更多地被视为前缀。
要启用媒体类型版本控制,你需要在 main.ts
文件中这样配置:
typescriptimport { NestFactory } from '@nestjs/core'; import { VersioningType } from '@nestjs/common'; import { AppModule } from './app.module'; async function bootstrap() { const app = await NestFactory.create(AppModule); app.enableVersioning({ type: VersioningType.MEDIA_TYPE, key: 'v=', }); await app.listen(3000); } bootstrap();
其中 key
属性应为包含版本的键值对的键和分隔符。例如,当 Accept
头部为 application/json;v=2
时,key
属性将设置为 v=
。
一个最基础接口版本的 Controller
typescriptimport { Controller, Get } from '@nestjs/common'; @Controller() export class UserControllerV1 { @Get('user') findAll(): string[] { return ['This action returns all user']; } }
接下来在这个基础接口的基础上进行多种方式的版本控制
可以为单个路由设置版本。单个路由的版本设置将覆盖控制器版本。以下实例演示了如何为路由添加版本:
typescriptimport { Controller, Get, Version } from '@nestjs/common'; @Controller() export class UserController { @Version('1') @Get('user') findAllV1(): string[] { return ['user1']; } @Version('2') @Get('user') findAllV2(): string { return ['user2']; } }
访问 http://localhost:3000/v1/user
分开到不同的Controller文件中
typescriptimport { Controller, Get, Version } from '@nestjs/common'; @Controller({ version: ['1'], }) export class UserController { @Get('user') findAll(): string[] { return ['user1']; } }
typescriptimport { Controller, Get, Version } from '@nestjs/common'; @Controller({ version: ['2'], }) export class UserController { @Get('user') findAll(): string[] { return ['user2']; } }
访问 http://localhost:3000/v1/user
typescriptapp.enableVersioning({ // ... defaultVersion: '1' // or defaultVersion: ['1', '2'] // or defaultVersion: VERSION_NEUTRAL });
有时候,一些控制器或路由可能无论版本如何都具有相同的功能。这时,你可以将版本设置为 VERSION_NEUTRAL
符号,任何版本的请求都将映射到该控制器或路由。以下实例演示了如何设置无视版本的控制器:
typescriptimport { Controller, Get, VERSION_NEUTRAL } from '@nestjs/common'; @Controller({ version: VERSION_NEUTRAL, }) export class UserController { @Get('user') findAll(): string[] { return return ['user']; } }
访问 http://localhost:3000/user
简单的版本控制可能会在管理上引入混乱和复杂性,但是 NestJS 的多版本控制能有效地处理这类问题,让我们可以使用 URI、标头或媒体类型的方式灵活地管理各个版本。不仅如此,NestJS 还允许我们对控制器或每个独立路由进行单独的版本控制,并提供了一种选择退出版本控制的方式。另外,我们还可以将默认版本全局应用于未指定版本的所有控制器和路由,进一步简化了版本管理工作。
使用 API 版本控制,我们能在新增功能和修复缺陷时保持旧版的稳定性,同时也允许用户在准备好更新他们的客户端时自由切换到新版本。通过优雅而规范的版本控制,开发者可以始终对 API 有清晰的理解,而用户则可以享受到连续的服务。
使用 NestJS 进行接口多版本的控制,是一种高效且灵活的解决方案。它不仅能帮助我们在持续迭代和更新中保持稳定,也使得我们的应用具有更好的可扩展性和健壮性。