Nx 環境で実践！Swagger 2.0 から Open API 3.0 への移行

これは [Hubble Advent Calendar 2024](https://qiita.com/advent-calendar/2024/hubble) の 10 日目の記事です。

## 自己紹介

2024 年 3 月から [株式会社 Hubble](https://hubble-docs.com/) のフロントエンドチームにジョインした  
[akihiko.KIgure a.k.a グレさん](https://x.com/ic_lifewood) です。  
現在は主にリファクタリング業務を担当しています。  
今回は、Swagger 2.0 定義から Open API 3.0 定義への移行作業についてご紹介します。

## 開発ツール

- フロントエンドのリポジトリは [Nx](https://nx.dev/) でモノレポ管理しています。
- フレームワークは [Angular](https://angular.dev/) を使用しています。
  - 今回は Angular 関連ライブラリの詳細な説明は省略します。

## どうして Open API 3.0 へ移行するのか？

1. サポート: Swagger 2.0 のメンテナンス停止、OpenAPI 3.0は継続更新。
1. 機能改善: リクエスト・レスポンスの型指定や詳細設定が可能。
1. 柔軟な定義: 複雑なAPIをモジュール化して再利用性向上。
1. ツール対応: 新しいツールやライブラリがOpenAPI 3.0を前提に設計。
1. 業界標準化: OpenAPI 3.0は広く採用され相互運用性が向上。

Swagger 2.0 のメンテナンス停止が最も大きな理由です。

## 基本的なリファクタリング手順

Nx を利用しているため、影響範囲を考慮しつつ以下の順序でリファクタリングを進めます。

1. `nx-workspace/libs/*` の各プロジェクト毎  
2. `nx-workspace/apps/*` の各プロジェクト毎


## Swagger 2.0 定義での開発状況

これまで以下の手法で開発を進めていました。

- [ng-swagger-gen](https://github.com/cyclosproject/ng-swagger-gen#readme) を利用して Angular 用コードを生成しています。
- 生成コード配置例
  - `nx-workspace/libs/shared/api`
    - 既存の Swagger 2.0 用ライブラリ
- YAML 定義内容
  - tag: 44  
  - operationID: 314  
- YAML 定義から生成された Angular 用コードのファイル数（spec.ts を除く）
  - service: 39  

## Open API 3.0 への移行

以下の手順で移行を進めました。

### 使用ツール

1. [swagger2openapi](https://github.com/Mermade/oas-kit#readme)  
   Swagger 2.0 を Open API 3.0 定義の YAML に変換します。  
   **※ 完全移行後は Swagger 2.0 YAML は不要になるため、作業終了時に削除予定です。**  

2. [ng-openapi-gen](https://github.com/cyclosproject/ng-openapi-gen#readme)  
   Open API 3.0 定義から Angular 用コードを生成します。  

### 差異の確認と修正ポイント

- Swagger 2.0 と Open API 3.0 では生成コードの引数や仕様に違いがあり、移行に伴い修正が必要になりました。


## Open API 3.0 移行作業の詳細

### Open API 用の新規ライブラリ作成

- ディレクトリ例
  - Swagger 2.0 用（`既存`）：nx-workspace/libs/shared/`api`
  - Open API 3.0 用（`新規`）：nx-workspace/libs/shared/`openapi`  

- Nx コマンドで新規ライブラリ作成
  ```bash
  $ npx nx generate @hubble-inc/workspace:library \
                 --name=shared-libs-openapi --scope=shared
  ```

### 移行作業の流れ

1. 各 tag 毎に以下の作業を実施します。
   - Open API 3.0 の参照パスに変更  
   - 引数修正  
   - Enum プロパティ修正  
   - ユニットテスト修正  

2. 全ての tag/operationID を移行後、以下を実行：  
   #### Swagger 2.0 ライブラリの削除
   ```bash
   $ npx nx generate @nx/workspace:remove --projectName=shared-libs-api
   ```

   #### Open API 3.0 ライブラリの移動  
   Open API 3.0 を正式採用とするためディレクトリ名を変更します。 
   ```bash
   $ npx nx generate @nx/workspace:move \
                 --destination=shared/libs/openapi \
                 --projectName=shared-libs-openapi \
                 --newProjectName=shared-libs-api \
                 --importPath=@shared/api
   ```

## 移行中に判明した課題

1. **Swagger 2.0 から Open API 3.0 に変換後の仕様エラー**  
   Open API 3.0 の仕様に沿わない定義が存在する場合、変換後に問題が判明することがあります。

2. **Angular 用コード生成時の問題**  
   定義エラーがエンドポイント疎通確認の際に発覚するケースが多いです。 
   適切な修正が必要になります。


### 具体例

#### `multipart/form-data` の問題

リクエストパラメータに `blob` を指定する場合、明示的に `multipart/form-data` を定義する必要あります。
```yaml
consumes:
  - multipart/form-data
```

#### パラメータ定義の順序問題

リクエストパラメータを operationId の前に定義すると、Angular 用コード生成時に反映されません。
```yaml
Bad（修正前）
/hoge/fuga:
  parameters: # operationId より前にパラメータ定義
    - in: body
      name: body
  post:
    operationId: hogeDelete

Good（修正後）
/hoge/fuga:
  post:
    operationId: hogeDelete
    parameters: # operationId より後にパラメータ定義
      - in: body
        name: body
```

## まとめ

- 移行の主な作業は下記の通りです。
  - エンドポイント引数やパス変更
  - Open API 3.0 用の yaml 定義修正
- Nx のコマンド利用により、人的ミスを削減し、効率的な開発が可能でした。

#### 本記事が以下の方々の参考になれば幸いです：

- Angular をモノレポで開発している方（Nx を利用中の方）  
- Swagger 2.0 から Open API 3.0 への移行を検討している方  

次回は [@moneyan9](https://qiita.com/moneyan9) さんです！よろしくお願いします！