如何在NestJs中构建多版本接口?

88 阅读2分钟

一、前言

在实际项目开发中,随着应用程序的迭代和用户需求的增加,原有的接口可能无法满足新的需求,或者需要进行较大的改动。这时,我们可以创建一个新的接口版本,而不是替换原来的接口。

这样,旧版本的客户端仍然可以使用原有的接口,而新版本的客户端则可以使用新的接口。

这种方式可以确保旧版本客户端的正常运行,同时也可以为新版本客户端提供更好的功能和性能。

此外,多版本接口也可以帮助我们在不影响现有功能的情况下添加新功能,这有助于降低开发和维护的成本。 多版本接口可以提高系统的可扩展性和灵活性,从而更好地满足用户的需求。

本文介绍下如何在NestJs中构建多版本接口?

二、具体实现

1、创建项目

首先,我们先创建一个NestJs项目:、

nest new versioned-interfaces

2、创建Version枚举类

进入项目目录,然后创建一个名为 Version 的枚举类,它将包含我们希望支持的所有接口版本号:

// src/common/enums/version.ts 
export enum Version { V1 = 'v1', V2 = 'v2', V3 = 'v3'}

3、创建VersionGuard自定义Guard

然后,我们将创建一个名为 VersionGuard 的自定义 Guard 类,用于验证接口版本。此 Guard 类将从请求头中读取接口版本号,并与我们支持的版本进行比较:

// src/common/guards/version.guard.ts 

import { CanActivate, ExecutionContext, HttpException, HttpStatus } from '@nestjs/common';
import { Observable } from 'rxjs';
import { versionRegex } from './version.utils';

export class VersionGuard implements CanActivate {
  private versionRegex: RegExp;

  constructor() {
    this.versionRegex = versionRegex();
  }

  canActivate(context: ExecutionContext): boolean {
    const request = context.switchToHttp().getRequest();
    const version = request.headers.version;

    if (!version) {
      throw new HttpException('Missing version header', HttpStatus.BAD_REQUEST);
    }

    const match = version.match(this.versionRegex);

    if (!match) {
      throw new HttpException('Invalid version header format', HttpStatus.BAD_REQUEST);
    }

    const majorVersion = match[1];
    const minorVersion = match[2];

    if (parseInt(majorVersion) > Version.V2 || (majorVersion === Version.V2 && minorVersion > 1)) {
      throw new HttpException(`Unsupported version: ${version}`, HttpStatus.FORBIDDEN);
    }

    return true;
  }
}

在我们的版本守卫类中,我们使用正则表达式从请求头中提取出接口版本号,并与我们支持的版本进行比较。如果请求头中没有指定版本或指定了不支持的版本,则会抛出相应的错误。

4、创建VersionUtils辅助类

接下来,我们将创建一个名为 VersionUtils 的辅助类,用于验证和格式化接口版本号:

// src/common/utils/version.utils.ts

export function versionRegex(version: string): RegExp {
  const [majorVersion, minorVersion = '0'] = version.split('.');
  return new RegExp(`^v${majorVersion}.${minorVersion}$`);
}

export function toVersion(version: string): Version {
  switch (version) {
    case 'v1':
      return Version.V1;
    case 'v2':
      return Version.V2;
    default:
      throw new Error(`Invalid version: ${version}`);
  }
}

5、创建多版本接口

最后,我们将对控制器进行装饰,以应用版本守卫。以下是一个示例控制器:

// src/controllers/hello.controller.ts

import { Controller, Get, Header, HttpException, HttpStatus } from '@nestjs/common';
import { VersionGuard } from '../guards/version.guard';

@Controller()
export class HelloController {
  constructor() {}

  @Get()
  @Header('version', '1') // 设置请求头,指定接口版本号为 v1
  @UseGuards(VersionGuard)
  helloV1() {
    return 'Hello, version 1!';
  }

  @Get()
  @Header('version', '2.1') // 设置请求头,指定接口版本号为 v2.1
  @UseGuards(VersionGuard)
  helloV2() {
    return 'Hello, version 2.1!';
  }
}

在上面的示例中,我们使用 @Header 装饰器设置请求头中的接口版本号,并使用 @UseGuards 装饰器将版本守卫应用于相应的路由。

至此,我们已经完成了构建多版本接口的所有步骤。通过使用版本守卫和请求头,我们可以轻松地为不同的接口版本提供支持,并确保只有符合要求的请求才能通过验证并访问相应的路由。