OpenAPI ファイル分割と GitHub Actions での自動デプロイ手順
概要
この記事では、OpenAPI 仕様書をファイル分割して管理し、GitHub Actions を使用して Redoc で HTML ドキュメントを生成し、AWS S3 に自動デプロイする手順を説明します。
前提条件
- Node.js 22 以上
- Docker
- AWS S3 バケット
- AWS IAM ロール(GitHub Actions 用)
1. OpenAPI ファイル分割の構造
ディレクトリ構成
backend/openapi/api/v1/
├── openapi.yml # メインのOpenAPIファイル
├── components/
│ ├── schemas.yml # データモデル定義
│ └── errors.yml # エラーレスポンス定義
└── paths/
└── v1/
└── users.yml
メイン OpenAPI ファイル(openapi.yml)
openapi: 3.0.0
info:
title: User Management API
description: API for User Management System
version: 1.0.0
servers:
- url: https://api.example.com/api
description: Production server
- url: https://api-staging.example.com/api
description: Staging server
paths:
/v1/users/{user_id}:
$ref: "./paths/v1/users.yml#/paths/~1v1~1users~1{user_id}"
components:
securitySchemes:
BearerAuth:
type: http
scheme: bearer
bearerFormat: UUID
schemas:
User:
$ref: "./components/schemas.yml#/components/schemas/User"
Error:
$ref: "./components/errors.yml#/components/schemas/Error"
security:
- BearerAuth: []
スキーマファイル(components/schemas.yml)
components:
schemas:
User:
type: object
properties:
id:
type: string
format: uuid
description: User unique identifier
name:
type: string
description: User name
email:
type: string
format: email
description: User email address
required:
- id
- name
- email
UserCreateRequest:
type: object
properties:
name:
type: string
description: User name
email:
type: string
format: email
description: User email address
required:
- name
- email
エラーレスポンスファイル(components/errors.yml)
components:
schemas:
Error:
type: object
properties:
message:
type: string
description: Error message
code:
type: string
description: Error code
required:
- message
- code
BadRequestError:
allOf:
- $ref: "#/components/schemas/Error"
- type: object
properties:
message:
example: "Bad Request"
code:
example: "BAD_REQUEST"
UnauthorizedError:
allOf:
- $ref: "#/components/schemas/Error"
- type: object
properties:
message:
example: "Unauthorized"
code:
example: "UNAUTHORIZED"
エンドポイントファイル(paths/v1/users.yml)
paths:
/v1/users/{user_id}:
get:
summary: Get user information
description: Retrieve user information by ID
tags:
- Users
security:
- BearerAuth: []
parameters:
- name: user_id
in: path
required: true
schema:
type: string
format: uuid
description: User unique identifier
responses:
"200":
description: User information retrieved successfully
content:
application/json:
schema:
$ref: "../../components/schemas.yml#/components/schemas/User"
"401":
description: Unauthorized
content:
application/json:
schema:
$ref: "../../components/errors.yml#/components/schemas/UnauthorizedError"
"404":
description: User not found
content:
application/json:
schema:
$ref: "../../components/errors.yml#/components/schemas/NotFoundError"
put:
summary: Update user information
description: Update user information
tags:
- Users
security:
- BearerAuth: []
parameters:
- name: user_id
in: path
required: true
schema:
type: string
format: uuid
description: User unique identifier
requestBody:
required: true
content:
application/json:
schema:
$ref: "../../components/schemas.yml#/components/schemas/UserCreateRequest"
responses:
"200":
description: User updated successfully
content:
application/json:
schema:
$ref: "../../components/schemas.yml#/components/schemas/User"
"400":
description: Bad request
content:
application/json:
schema:
$ref: "../../components/errors.yml#/components/schemas/BadRequestError"
"401":
description: Unauthorized
content:
application/json:
schema:
$ref: "../../components/errors.yml#/components/schemas/UnauthorizedError"
"404":
description: User not found
content:
application/json:
schema:
$ref: "../../components/errors.yml#/components/schemas/NotFoundError"
2. Redoc 環境の構築
package.json
{
"name": "user-api-docs",
"version": "1.0.0",
"description": "Redoc documentation for User Management API",
"scripts": {
"start": "redocly preview-docs --port 8080 --host 0.0.0.0",
"build": "redocly build-docs",
"build:json": "redocly bundle --ext json",
"dev": "redocly preview-docs --watch --host 0.0.0.0"
},
"dependencies": {
"@redocly/cli": "^2.0.2"
},
"keywords": ["redoc", "openapi", "documentation"],
"author": "",
"license": "MIT"
}
Dockerfile
FROM node:22-alpine
WORKDIR /app
RUN npm install -g npm@11.5.2
RUN addgroup -g 1001 -S nodejs && \
adduser -S redoc -u 1001
RUN chown -R redoc:nodejs /app
USER redoc
Docker Compose 設定(compose.yml)
services:
redoc:
build: .
container_name: user-api-redoc
ports:
- "8080:8080"
volumes:
- ../..:/workspace:ro
- .:/app
working_dir: /app
command: sh -c "mkdir -p public && npx redocly bundle /workspace/backend/openapi/api/v1/openapi.yml --output public/openapi.json --ext json && npx redocly preview-docs public/openapi.json --port 8080 --host 0.0.0.0"
restart: unless-stopped
Makefile
DOCKER_IMAGE = user-api-redoc
JSON_OUTPUT = public/openapi.json
HTML_OUTPUT = public/index.html
.PHONY: build html serve clean
build:
mkdir -p public
docker run --rm -v $(PWD)/../..:/workspace -v $(PWD):/app -w /app $(DOCKER_IMAGE) npx redocly bundle /workspace/backend/openapi/api/v1/openapi.yml --output $(JSON_OUTPUT) --ext json
html: build
docker run --rm -v $(PWD):/app -w /app $(DOCKER_IMAGE) npx redocly build-docs $(JSON_OUTPUT) --output $(HTML_OUTPUT)
serve: build
docker run --rm -v $(PWD)/../..:/workspace -v $(PWD):/app -w /app -p 8080:8080 $(DOCKER_IMAGE) npx redocly preview-docs $(JSON_OUTPUT) --port 8080 --host 0.0.0.0
clean:
rm -rf public/
3. GitHub Actions 設定
.github/workflows/upload_openapi.yml
name: Upload OpenAPI Documentation
on:
push:
branches:
- develop
- master
jobs:
build_and_upload_redoc:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "22"
cache: "npm"
cache-dependency-path: tools/redoc/package-lock.json
- name: Install dependencies
run: npm ci
working-directory: ./tools/redoc
- name: Build Redoc Documentation
run: |
mkdir -p public
npx redocly bundle ../../backend/openapi/api/v1/openapi.yml --output public/openapi.json --ext json
npx redocly build-docs public/openapi.json --output public/index.html
working-directory: ./tools/redoc
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-region: ap-northeast-1
role-to-assume: arn:aws:iam::YOUR_ACCOUNT_ID:role/user-api-docs-deployment-role
role-session-name: GHAUploadOpenAPIDocDeployment
- name: Publish to AWS S3
env:
S3_BUCKET: user-api-docs-bucket
run: |
aws s3 sync --delete ./public s3://${{ env.S3_BUCKET }}/${{ github.ref_name }}/api_docs
working-directory: ./tools/redoc
4. AWS 設定
IAM ロールの作成
GitHub Actions 用の IAM ロールを作成し、以下のポリシーをアタッチします:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:PutObjectAcl",
"s3:GetObject",
"s3:DeleteObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::user-api-docs-bucket",
"arn:aws:s3:::user-api-docs-bucket/*"
]
}
]
}
S3 バケットの設定
- S3 バケットを作成
- 静的ウェブサイトホスティングを有効化
- バケットポリシーでパブリック読み取りを許可
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::user-api-docs-bucket/*"
}
]
}
5. 使用方法
ローカル開発
cd tools/redoc
make build # JSON変換
make html # HTML生成
make serve # 開発サーバー起動
ブラウザで http://localhost:8080 にアクセスしてドキュメントを確認できます。
自動デプロイ
-
developまたはmasterブランチにプッシュ - GitHub Actions が自動実行
- OpenAPI ファイルが統合され、Redoc で HTML 生成
- S3 に自動アップロード
まとめ
この手順に従うことで、OpenAPI 仕様書を効率的に管理し、自動的にドキュメントを生成・デプロイできます。ファイル分割により保守性が向上し、GitHub Actions による自動化で開発効率が大幅に改善されます。