本記事は、私が携わったとある案件で利用していたAPIドキュメントを整備した際の記録です。
APIドキュメントの管理に困っている方の参考になればと思います。
もともとスプレッドシートで管理していたのですが、スプレッドシートの管理だと、差分を見るのが大変だったり、他社に利用してもらいにくいなど不便な点がありました。
またOpenAPIの仕様に合わせた記述をしたいという要望があったため、YAML + OpenAPIでの管理へ移行することとなりました。
OpenAPIへの記述へ移行するに当たり、YAMLで書いた仕様書を何かしらの方法でレンダリングする必要がありました。候補としては、Redoc、Swagger UIが上がり、当初はSwagger UIを導入する予定だったのですが、いくつかの理由がありRedocを採用する形となりました。
今回の要件として、静的ファイル(HTML, CSS, JavaScript)をAmazon S3に配置して、参照したいという要望がありました。
しかし、Swagger UIは基本的にサーバーありきで実装する形となっており、静的ファイルとして出力する場合はSwagger UIの出力ファイルであるswagger-ui-distをダウンロードしてきて、書き換える必要がありました。
参考:実装手順
参考:Swagger UI Repo
この直接ファイルを修正するという作業があるとswagger-ui-distが更新された場合に、自身がファイルを修正して再アップロードする必要があり、非常に困っておりました。
そこで色々と探していたところRedocというライブラリを発見しました。
参考:Redoc
Redocでは、コマンド一発でYAMLから単一HTML(出力されるHTML内にCSS、JavaScriptが梱包されている) への変換が可能なので、swagger-ui-distと比べてHTMLファイルを直接触る必要がありませんでした。
他にもRedocはswagger-ui-distと比べたとき、
といったメリットもあり、今回はRedocを採用することとなりました。
Amazon S3に設置するとのことだったので、CDを行うためのサービス候補としては、下記の2つがありました。
メインのプロジェクトでAWS CodePipelineを利用して使い慣れていたことと、Amazon S3との相性が良いことから、今回はAWS CodePipelineを採用しました。
構成としては
の形にしました。
動作は以下の順番で行われます。
APIドキュメントを確認する際には、そのままAmazon S3の公開URLを提供する形にしました。
Redoc側ではファイル構成が決まっていないため、以下のような構成にしました。src内のデータをビルドして、outに出力する構成です。掲載する画像に関しては、参照がズレないようoutと同じパスに設置しています。
Redocがnpmパッケージで管理されていたので、npmで管理、npm scriptsで出力するようにしました。
references
├── aws
│ └── buildspec.yaml
├── README.md
├── out
│ ├── output.html
│ └── images
│ ├── img1.png
│ └── img2.png
├── package-lock.json
├── package.json
└── src
├── src.yaml
└── images
├── img1.png
└── img2.png
AWS CodePipelineから処理を受け取った後、リポジトリ内にあるaws/buildspec.yamlをAWS CodeBuildが参照します。
YAML構成は、
version: 0.2
phases:
install:
runtime-versions:
nodejs: latest
pre_build:
commands:
- cd references
- npm install
build:
commands:
- npm run build
- cd ${CODEBUILD_SRC_DIR}
artifacts:
type: zip
files:
- "**/*"
base-directory: references/out
となっています。
buildspec.yamlでは、phase内にある動作を順番に実行します。
最後のartifactsでは、ビルド後にどうファイルを出力するかの指定ができます。
今回の場合は、references/out以下のファイルをzipファイルで固めた後、AWS Code Pipelineへ処理にしています。
他にも項目はあるので、詳細は公式リファレンスを参照してください。
参考:公式リファレンス
AWS CodeBuildのbuildフェーズで動作させているコマンドは、npm scriptsで指定しているbuildコマンドで、OpenAPIの仕様に則ったYAMLファイルをHTMLファイルへ変換しています。
ポイントとしてnpm scriptsではprebuild、postbuildコマンドを定義しておくと、buildの前後で実施してくれます。build内にワンライナーで書いてもよいですが、大量のコマンドを並べる必要がある場合は、分離したほうが分かりやすいと思います。
他コマンドについてはbuild内の一部コマンドとして利用しています。
本案件では、開発者の開発環境がWindows / Mac環境でした。
なので、削除コマンド、コピーコマンドに関しては以下のライブラリを利用して、プラットフォーム間の差異を吸収しています。
以下がpackage.jsonの中身となっております。
"scripts": { "prebuild": "npm run clean", "build": "npm run _bundle-yaml-from-source && npm run _create-redoc", "postbuild": "npm run _copy-binaries", "clean": "rimraf out && mkdir out && echo $null > ./out/.gitkeep", "lint": "npx openapi lint ./src/src.yaml", "preview": "npx openapi preview-docs ./src/src.yaml", "_bundle-yaml-from-source": "npx openapi bundle src/src.yaml --output ./out/out.yaml ", "_create-redoc": "npx redoc-cli bundle ./out/bundled.yaml -o out/output.html --options.theme.colors.primary.main=red && rimraf ./out/out.yaml", "_copy-binaries": "npx cpx ./src/images/**/* ./out/images/" }
AWS CodeBuildから渡されたzipファイルをAmazon S3へ渡すだけなのですが、注意点が2つあります。
AWS CodeBuild側からはzipファイルとしてデータが送られ来ているので、Amazon S3にzipファイルを解凍した状態で設置したい場合「デプロイする前にファイルを抽出する」にチェックを入れる必要があります。
このチェックを入れなかった場合、zipファイルがAmazon S3に直接アップロードされるだけになります。
Amazon S3側の権限でAWS CodePipelineから触れるようにしておかないと、Amazon S3アップロード時に弾かれます。
また、特定の利用者にのみ公開したいという要望があったため、閲覧制限も設ける必要がありました。
今回のケースだと実装工数の関係で、IP制限を設けて対応することになりました。
参考:実装手順
上記設定を行うことで、GitHubからAmazon S3へのHTMLデプロイまで、1通り実施することができました。ただし、2点ほどうまく行かなかった点があったので、そこは次回以降の注意点として気をつけて行きたいと考えています。
Amazon S3でIP制限を設けたのは良かったのですが、AWS CodePipelineにだけ権限を上げればよいのでは?
と考え、権限をAWS CodePipelineからのアクセスのみにしたところ、自分が締め出されました…😱
これ以降、自分の権限ではアクセスできなくなってしまったので、運用保守チームへ連絡して対応してもらうことになりました。権限を絞る時は自分が継続して触れる権限になっているかの確認を行いましょう。
本来であればGitHubのリポジトリPush時にOpenAPIのlintをかけて、不正なYAML構造である場合にリジェクトする処理を追加で入れ込みたかったのですが、時間の関係でできませんでした。
ただし、GitHubのissueとして切り出しておいたので、対応自体は今後の改修でしてもらえそうな感じになっています。間に合わないけどやっておいたほうが良い作業はissueに切り出すの、大事。
今回は、CDの流れを1通り自分で実装できたことがとても良かったと感じております。
GitHub Actionsを利用してCDを構築したことは経験がありましたが、AWS CodePipelineの構築(利用はしていた)は初めてだったので、サービス間の違いが知れて良かったです。
書き方はもちろんですが、AWS CodePipelineだとArtifact(受け渡し用zipファイル)を利用してStep間のデータ受け渡しを行う点が大きく違うと感じました。
PJとしては、運用保守チームに自ら志願して、今回の対応を任せてもらえたことが良かったです。対応に困ったときにも弊社メンバーが積極的にフォローをしてくれました。改めて、メンバー間のフォローはPJにおいて大切だと感じました。
ちょっとしたお願いからつながった話なので、面白そうな話があれば自分から聞いてみることが、一番大事かもしれないですね。