🦁

Nest.js Version8がリリースされたので新機能についてまとめる : API Versioning編

2021/07/23に公開

Nest.js Version 8が7月7日にリリース!

https://trilon.io/blog/announcing-nestjs-8-whats-new

新機能: API Versioning

Controller及び各Routesをバージョン管理できるようになりました。

1.URI Versioning

URIの中にVersion情報を含める。

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

const app = await NestFactory.create(AppModule);
app.enableVersioning({
  type: VersioningType.URI,
});
// OK!! http://localhost:3000/v1

Version管理の細かい話などはSemantic Versioning等を参照するといいかもしれない。
https://semver.org/lang/ja/


prefixは明示に指定しない限りv1,v2となるようです。

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

const app = await NestFactory.create(AppModule);
app.enableVersioning({
  type: VersioningType.URI,
  //ここで別途prefixを指定できる。
  prefix:"ver"
  
 // OK!! http://localhost:3000/ver1
 // Error!! http://localhost:3000
});

2.Header Versioning

headerで指定したrequest headerにversion情報を含める。

app.enableVersioning({
  type: VersioningType.HEADER,
  header: 'x-Api-Version',
});

requestにカスタムヘッダーを追加するmiddleware

import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, NextFunction } from 'express';

@Injectable()
export class VersioningMiddleware implements NestMiddleware {
  use(req: Request, next: NextFunction) {
    req.headers['x-API-Versioning'] = API_VERSION
    next();
  }
}

3.MediaType Versioning

Request時Accept HeaderにVerison情報を含める。

app.enableVersioning({
  type: VersioningType.MEDIA_TYPE,
  key: 'v=',
});

Version情報はセミコロンで区切る。
上記例の場合、Accept HeaderをAccept: application/json;v=1という風に指定する。

Version指定

Controllerにversionを宣言するやり方と、各Routeにversionを宣言するやり方がある。

import { Controller, Get, Version } from '@nestjs/common';
import { AppService } from './app.service';

@Controller({ version: '1' })
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get()
  getHello(): string {
    return this.appService.getHello();
  }
  
  // OK!! http://localhost:3000/v1
  // Error!! http://localhost:3000/v2
  
  @Get('/bye')
  @Version('2')
  getBye() {
    return this.appService.getBye();
  }
  
  // OK!!  http://localhost:3000/bye/v2
  // Error!! http://localhost:3000/bye/v1
}

Controllerのバージョン宣言より、各Routesのversion宣言が優先されます。

従って現状Controllerでメジャーバージョンを、Routesでマイナーバージョンを管理。
といった運用はできないみたいです。

https://github.com/nestjs/nest/pull/6278

また、Versionは配列で指定したり、そもそもVersion管理をする必要が無いEndpointには
VERSION_NEUTRALを指定することも可能です。

import { Controller, Get, Version, VERSION_NEUTRAL } from '@nestjs/common';
import { AppService } from './app.service';

@Controller({ version: ['1', '2'] })
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get()
  getHello(): string {
    return this.appService.getHello();
  }
  
  // OK!! http://localhost:3000/v1
  // OK!! http://localhost:3000/v2
  
  @Get('/bye')
  @Version(VERSION_NEUTRAL)
  getBye() {
    return this.appService.getBye();
  }
}

// OK!! http://localhost:3000/bye
// Error!! http://localhost:3000/bye/v1

最後に

API Versioning自体は賛否両論ありますが、Nest.jsという個人的に好きなFWにメジャーアップデートが来たのが何よりうれしいですね!!
他にもV8の新機能としてServerless環境での運用の際に役立ちそうなlazy-loadingや,
Log機能にもアップデートが入ってるみたいなので後日まとめようと思います!

Discussion