OpenAPI Specificationの分割・統合

こんにちは。システム開発推進部の牛崎です。

Web API開発で最初に考えたいIF定義。昨今はREST API定義を記述するOAS (OpenAPI Specification)が登場し、テキストベースで手軽にIF定義を編集出来るようになりました。以前はSwaggerと呼ばれていたものです。OASのIF定義で真っ先に懸念されるのが肥大化で、作成経験のある方はIF定義の分割・統合を考えたことがあるのではないでしょうか?

僕の所属するGX推進グループは、今後Web APIとのお付き合いが長くなるはず。OASどのようにIF定義を分割・統合すると楽そうか? 検討・検証をしてみました。

まずは統合の雰囲気を知ろう

OAS編集ツールのStoplight Studioを使ってみましょう。 プロジェクト新規作成からチュートリアルプロジェクトを作成可能です。このプロジェクトのディレクトリ構造を参考に進めます。

.
|-- assets
|   `-- images
|       `-- studio-overview.png
|-- docs
|   |-- introduction.md
|   |-- markdown
|   |   |-- basic-syntax.md
|   |   `-- stoplight-flavored-markdown.md
|   `-- ui-overview.md
`-- reference
    |-- common
    |   |-- models
    |   |   `-- error.v1.yaml
    |   `-- openapi.v1.yaml
    |-- petstore
    |   |-- models
    |   |   |-- category.v1.yaml
    |   |   `-- pet.v1.yaml
    |   `-- openapi.v1.yaml
    `-- todos
        |-- models
        |   |-- todo-full.v1.json
        |   |-- todo-partial.v1.json
        |   `-- user.v1.json
        `-- openapi.v1.json

reference以下に機能グループでpetstoreとtodosに分けられ、それぞれにIF定義本体のopenapi.v1.yaml (json)があります。 これらの機能グループがまとまって1つのアプリケーションになると仮定し、2つのIF定義を統合して1つにしてみましょう。

ルートとなるIF定義として./reference/openapi.v1.yaml、統合後のIF定義を出力するディレクトリとして./reference/bundleを作成。

.
`-- reference
    |-- bundle
    `--  openapi.v1.yaml

./reference/openapi.v1.yamlにpetstoreとtodosのIFを参照で記載して、swagger-cliを実行してみます。

f:id:ms_ko_ushizaki:20210831142428p:plain
reference/openapi.v1.yaml

$ cd reference
$ swagger-cli bundle -o ./bundle/openapi.v1.yaml -t yaml ./openapi.v1.yaml

./referenence/bundle/openapi.v1.yamlが出力され、各機能グループに定義されたIFが統合されました。一安心 (^^; ※1

f:id:ms_ko_ushizaki:20210831142549p:plain
reference/bundle/openapi.v1.yaml
※1 よく見たらpetstoreがOAS v3.x・todosがOAS v2.xだったので正常動作しないのではないかと...

次は分割・統合してみよう

petstoreのopenapi.v1.yamlはIFが2つのみですが、全体は92行。全体を見渡すのに不便ですし、これだけでも肥大化しやすいと分かります。

大部分を占めるpathsセクションを分割して、スリムにしてみましょう。 分割したpathsを配置するディレクトリ./reference/petstore/pathsと、petstoreの統合後IF定義を出力するディレクトリ./reference/petstore/bundleを作成。

.
|-- bundle
|-- models
|   |-- category.v1.yaml
|   `-- pet.v1.yaml
|-- openapi.v1.yaml
`-- paths
    |-- paths.pets.by-petId.yaml
    `-- paths.pets.yaml

./reference/petstore/openapi.v1.yamlのpathsは、pathsディレクトリ以下の各IF定義を参照とし、統合してみます。

f:id:ms_ko_ushizaki:20210910184250p:plain
reference/petstore/openapi.v1.yaml

$ cd ./reference/petstore
$ swagger-cli bundle -o ./bundle/openapi.v1.yaml -t yaml ./openapi.v1.yaml

petstoreのIF定義が統合されました。

f:id:ms_ko_ushizaki:20210830195539p:plain
reference/petsotre/bundle/openapi.yaml

最後に、ルートとなる./reference/openapi.v1.yamlがpetstoreの参照先を統合後のIF定義に変更し、こちらも再統合してみましょう。

f:id:ms_ko_ushizaki:20210830200040p:plain
reference/openapi.v1.yaml
正常に統合できました。ヤッタネ!!
f:id:ms_ko_ushizaki:20210830200109p:plain
reference/bundle/openapi.v1.yaml

まとめ

今回は以下の分割・統合の流れを試しました。複数機能グループを1ファイルに統合する運用とするなら、現実的に使えそうな気がします。

  1. 中間成果物として機能毎に統合IF定義を出力する
  2. 中間成果物を統合してルートIF定義を出力する

皆さんもIF定義を楽しく進めて、良いWeb APIライフを!!

牛崎 洸システム開発部 開発グループ エンジニア