⛓️

GitHub ActionsによるAPI仕様書のGitHub Pagesへの自動デプロイ

2023/10/28に公開

環境

macOS: Ventura 13.5
Redoc: 0.13.21
OpenAPI: 3.1

今回の成果物

以下のようなAPI仕様書をGitHub Pagesにデプロイします。

https://takumi-pro.github.io/api-document-auto-deploy-sample/

コードはこちらです。
https://github.com/takumi-pro/api-document-auto-deploy-sample

API仕様書の作成

API仕様書はStoplightというツールを使用して作成します。

https://stoplight.io/

StoplightはAPI仕様書をGUIで操作して作成できる便利なツールです。
プロジェクトを作成する際にAdd from GitHubを選択するとStoplight上からcommitやpushが可能になります。API仕様書が作成できたら、メニューのCommit & Publishを押すとリモートリポジトリに変更が反映されます。

今回作成したAPI仕様書です。

TODO-List-API.yaml
openapi: 3.1.0
x-stoplight:
  id: ss3n3y2319sb9
info:
  title: TODO List API
  version: '1.0'
servers:
  - url: 'http://localhost:3000'
paths:
  /tasks:
    get:
      summary: Get All Task
      tags: []
      responses:
        '200':
          $ref: '#/components/responses/Tasks'
        '400':
          $ref: '#/components/responses/400_bad_request'
        '500':
          $ref: '#/components/responses/500_internal_server_error'
      operationId: get-tasks
      x-stoplight:
        id: wpakhnx6w0jfi
      description: ''
    post:
      summary: Create Task
      operationId: post-tasks
      responses:
        '200':
          $ref: '#/components/responses/Task'
        '400':
          $ref: '#/components/responses/400_bad_request'
        '500':
          $ref: '#/components/responses/500_internal_server_error'
      x-stoplight:
        id: fyiltn0fialfa
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                title:
                  type: string
                  x-stoplight:
                    id: 17cj9oiqrgzu0
                description:
                  type: string
                  x-stoplight:
                    id: c6hwnnrc9fiq7
              required:
                - title
  '/tasks/{taskId}':
    parameters:
      - schema:
          type: string
        name: taskId
        in: path
        required: true
    get:
      summary: Get Task
      tags: []
      responses:
        '200':
          $ref: '#/components/responses/Task'
        '400':
          $ref: '#/components/responses/400_bad_request'
        '500':
          $ref: '#/components/responses/500_internal_server_error'
      operationId: get-tasks-taskId
      x-stoplight:
        id: 28r5wgjwjf2w8
      requestBody:
        content: {}
    put:
      summary: Update Task
      operationId: put-tasks-taskId
      responses:
        '200':
          $ref: '#/components/responses/Tasks'
        '400':
          $ref: '#/components/responses/400_bad_request'
        '500':
          $ref: '#/components/responses/500_internal_server_error'
      x-stoplight:
        id: 5p39wgjzwshxo
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                title:
                  type: string
                  x-stoplight:
                    id: 1nw8g6fnawx2k
                description:
                  type: string
                  x-stoplight:
                    id: siscnpp7s54te
              required:
                - title
    delete:
      summary: Delete Task
      operationId: delete-tasks-taskId
      responses:
        '200':
          $ref: '#/components/responses/Task'
        '400':
          $ref: '#/components/responses/400_bad_request'
        '500':
          $ref: '#/components/responses/500_internal_server_error'
      x-stoplight:
        id: jop88jodwb2dn
components:
  schemas:
    User:
      title: User
      type: object
      examples:
        - id: 142
          firstName: Alice
          lastName: Smith
          email: alice.smith@gmail.com
          dateOfBirth: '1997-10-31'
          emailVerified: true
          signUpDate: '2019-08-24'
      x-stoplight:
        id: 8o7p75nvr73zn
      properties:
        id:
          type: integer
          description: Unique identifier for the given user.
          x-stoplight:
            id: xd0xoj8k2eb86
        email:
          type: string
          format: email
          x-stoplight:
            id: hxrq8mjc728bj
        username:
          type: string
          x-stoplight:
            id: n6lq29ml83wfx
      required:
        - id
        - email
        - username
      description: ''
    Task:
      title: Task
      x-stoplight:
        id: ll9m3t69a6caf
      type: object
      properties:
        id:
          type: string
          x-stoplight:
            id: gqeu0e9edhshh
        title:
          type: string
          x-stoplight:
            id: smnuyaf8ei2zt
        description:
          type: string
          x-stoplight:
            id: tzqroj3fcrpf6
      required:
        - title
    Error:
      title: Error
      x-stoplight:
        id: igt1fjsrzqdij
      type: object
      properties:
        error:
          type: object
          x-stoplight:
            id: 524pzryjecb4r
          properties:
            message:
              type: string
              x-stoplight:
                id: rsp199ztgz5yh
            code:
              type: integer
              x-stoplight:
                id: nv8o1z3rik7z9
  responses:
    400_bad_request:
      description: Example response
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            Example 1:
              $ref: '#/components/examples/400_bad_request'
    Tasks:
      description: Example response
      content:
        application/json:
          schema:
            type: object
            properties:
              tasks:
                type: array
                x-stoplight:
                  id: ards5edeq7ghg
                items:
                  $ref: '#/components/schemas/Task'
                  x-stoplight:
                    id: ckr2x5jtuqbih
          examples:
            Example 1:
              $ref: '#/components/examples/Tasks'
    500_internal_server_error:
      description: Example response
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            Example 1:
              $ref: '#/components/examples/500_internal_server_error'
    Task:
      description: Example response
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Task'
          examples:
            Example 1:
              value:
                id: string
                title: string
                description: string
  examples:
    400_bad_request:
      value:
        error:
          message: 400 Bad Request
          code: 400
    Tasks:
      value:
        tasks:
          - id: string
            title: string
            description: string
    500_internal_server_error:
      value:
        error:
          message: 500 Internal Server Error
          code: 500
    Task:
      value:
        id: string
        title: string
        description: string
    Task_request:
      value:
        title: string
        description: string
  requestBodies: {}

workflowの作成

作成したyamlファイルのAPI仕様書をhtmlファイルに変換してGitHub Pagesにデプロイするworkflowを書いていきます。
htmlファイルへの変換にはRedocというツールを使用します。

https://github.com/Redocly/redoc

GitHub Pagesへのデプロイにはpeaceiris/actions-gh-pages@vを使用します。

https://github.com/peaceiris/actions-gh-pages

以下がworkflowを記述したyamlファイルです。

name: API Document Hosting

on:
  push:
  workflow_dispatch:

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v2

      - name: Convert YML to HTML
        run: |
          npm install -g redoc-cli
          redoc-cli bundle reference/TODO-List-API.yaml -o ./docs/index.html

      - name: Deploy to GitHub Pages
        uses: peaceiris/actions-gh-pages@v3
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: ./docs

Convert YML to HTMLでredocコマンドをインストールし、API仕様書をdocsディレクトリ配下にindex.htmlとして出力しています。GitHub Pagesにデプロイした際に、トップページでAPI仕様書を表示させたいのでファイル名はindexにしています。

変更をpushすると、workflowが実行されgh-pagesブランチができているはずです。

GitHub Pagesの設定

作成されたgh-pagesブランチの/(root)を公開するように設定します。

以下のように公開したサイトへのリンクが表示されていればOKです。

GitHubで編集を提案

Discussion