0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

OpenAPI ファイル分割と GitHub Actions での自動デプロイ手順

Last updated at Posted at 2025-10-28

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 バケットの設定

  1. S3 バケットを作成
  2. 静的ウェブサイトホスティングを有効化
  3. バケットポリシーでパブリック読み取りを許可
{
  "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 にアクセスしてドキュメントを確認できます。

自動デプロイ

  1. developまたはmasterブランチにプッシュ
  2. GitHub Actions が自動実行
  3. OpenAPI ファイルが統合され、Redoc で HTML 生成
  4. S3 に自動アップロード

まとめ

この手順に従うことで、OpenAPI 仕様書を効率的に管理し、自動的にドキュメントを生成・デプロイできます。ファイル分割により保守性が向上し、GitHub Actions による自動化で開発効率が大幅に改善されます。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?