「Nest.jsのSwaggerが3.0(OpenAPI)に対応するぞ!!!」でも記載しましたが、nestjs/swaggerの4系がリリースされ、正式にSwagger3.0(OpenAPI)に対応しました!!!
今回は、nestjs/swaggerの3系から4系へのバージョンアップしたときの手順を備忘録がてら書いておこうと思います。
nestjs/swaggerのバージョンアップ
nestjs/swaggerの最新版をインストールします
npm i --save @nestjs/swagger@latest
コードの修正
アノテーションの変更
リファレンスにも書いてありますが、いくつかアノテーションが変更になっているため、置換します。
The following decorators have been changed/renamed:
- @ApiModelProperty is now @ApiProperty
- @ApiModelPropertyOptional is now @ApiPropertyOptional
- @ApiResponseModelProperty is now @ApiResponseProperty
- @ApiImplicitQuery is now @ApiQuery
- @ApiImplicitParam is now @ApiParam
- @ApiImplicitBody is now @ApiBody
- @ApiImplicitHeader is now @ApiHeader
- @ApiOperation({ title: 'test' }) is now@ApiOperation({ summary: 'test' })
- @ApiUseTags is now @ApiTags
@ApiOperation
だけは、なぜかオプションのプロパティ名が変更になっているため注意です。
DocumentBuilderのオプション変更
DocumentBuilderにて、いくつかの関数が変更/追加/削除されているため対応します。
DocumentBuilder breaking changes (updated method signatures):
- addTag
- addBearerAuth
- addOAuth2
- setContactEmail is now setContact
- setHost has been removed
- setSchemes has been removed
The following methods have been added:
- addServer
- addApiKey
- addBasicAuth
- addSecurity
- addSecurityRequirements
setGlobalPrefixを使っている場合
リファレンスに記載がありますが、GlobalPrefixを使っている場合はオプションでignoreGlobalPrefix: true
を指定する必要があります。
これを指定しないと、http://localhost:3000/api/api/hello
みたいにプレフィクスが重複します。
↓修正例
const apiPrefix = '/api/v1';
app.setGlobalPrefix(apiPrefix);
const options = new DocumentBuilder()
・・・
.addServer(apiPrefix)
.build();
SwaggerModule.createDocument(app, options, { ignoreGlobalPrefix: true });
プラグインの設定
プラグインがいくつか使えるようになりました。
これにより、DTOクラスにアノテーションを指定する必要がなくなったり、class-validator
のいくつかのアノテーションをSwaggerに取り込んでくれるようになります。
{
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"plugins": [
{
"name": "@nestjs/swagger/plugin",
"options": {
"classValidatorShim": true
}
}
]
}
}
オプションとして、以下を指定することができます
-
dtoFileNameSuffix
:dtoファイルのサフィックスを指定できます(デフォルトは.dto.ts
,.entity.ts
) -
controllerFileNameSuffix
:コントローラーファイルのサフィックスを指定できます(デフォルトは.controller.ts
) -
classValidatorShim
:class-validatorのアノテーションを有効にする場合はtrue(デフォルトはfalse)- バリデーションについてはこちらを参照
openapi-generatorを使ってAPIクライアントを生成している場合
nestjs/swagger3系で出力されるSpecファイルを使っていた場合、生成されるAPIクライアントの関数名はデフォルトで{パス}{メソッド}
でした。
4系になり、operationIdにコントローラーの関数名がセットされ、その名称でAPIクライアントが生成されるため、クライアントサイドでfunction not found
が大量に発生しました。。。
【バージョンごとの出力例】
バージョン | URL | メソッド | コントローラーの関数名 | 出力されるAPIクライアント |
---|---|---|---|---|
3系 | /hello/world | GET | getMessage() | helloWorldGet() |
4系 | /hello/world | GET | getMessage() | getMessage() |
対応
-
@ApiOperation
でoperationId
を指定する - コントローラーの関数名を元のAPIクライアント名に変更
- コントローラーの関数名でクライアントサイドの呼び出し箇所を置換する
幸いまだリリース前のプロジェクトで大幅な変更も受け付けられるので3を採用しました。
バグ?
DTOファイルでエンティティファイルをインポートすると、リファレンスエラーになりました。
対象ファイル(ビルド後)は↓のような感じで、test_entity_1.default
がないと怒られます。
Object.defineProperty(exports, "__esModule", { value: true });
const openapi = require("@nestjs/swagger");
const class_validator_1 = require("class-validator");
class TestDto {
}
__decorate([
openapi.ApiProperty({ required: true, type: () => require("../models/test.entity").default }),
__metadata("design:type", test_entity_1.default)
], TestDto.prototype, "apply", void 0);
よく見るとrequire("../models/test.entity")
をtest_entity_1に設定する処理がありません。。。
とりあえず、@ApiProperty({type: Test})
のように直接型を指定すれば回避できますが、イケてないですね。。。
そもそもエンティティファイルをDTOファイルでインポートするな!ということなんでしょうか?
今後のバージョンアップに期待しましょう。
まとめ
割と簡単にバージョンアップができました。
今回のバージョンアップでOpenAPIに対応しただけじゃなく、DTOやレスポンス等の一部のアノテーションを省略できるようになったのはかなり大きいと思います。