3
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?

More than 1 year has passed since last update.

GitHub Actionsを使ってAPI設計をフロントエンドと共有する話

Posted at

はじめに

以下記事を読んで、OpenAPI Specをもっとフロントエンド側で活用できたら良いなと思いました。

そこで、同じようにGitHub Actionsを使って、GitHub PagesにReDocを配置、Mock Server(Prism)をCloud Runへデプロイしてみることにしました。

なお、Mock Server(Prism)のデプロイ先をCloud Runにしたのは、最小インスタンスを0にする(つまり、アクセスが無い時はインスタンスが落ちている状態にできる)ことができ、課金を抑えられると思ったからです。

ReDocとは?

ReDocは、OpenAPI Specからドキュメントを生成してくれるツールです。

同じようなツールで、Swagger UIもありますが、Swagger UIはリファレンス要素が強く、ReDocはガイド要素が強い(見易さ重視)印象を受けました。そのため、ドキュメントとして参照するならReDocの方が良いと思いました。

OpenAPI SpecからReDocを静的HTMLとして出力するには、 redoc-cli を使用します。

yarn add -D redoc-cli

// -o オプションを付けて静的HTMLとして出力する
redoc-cli bundle ${OpenAPI Spec Yaml} -o docs/index.html

↓静的HTMLで出力したReDoc
静的HTMLで出力したReDoc

Mock Server(Prism)

Prismは、OpenAPI SpecからMock Serverを構築してくれるツールです。

PrismはNode.jsで動くので、ローカル環境で動かすことができます。

yarn add -D @stoplight/prism-cli

prism mock ${OpenAPI Spec Yaml} -h 0.0.0.0 -p 8080

これをCloud Runにアップして動かすには、Dockerコンテナで動かす必要があります。
なので、以下のような Dockerfile を用意します。

FROM node:16

WORKDIR /openapi

COPY ${OpenAPI Spec Yaml} .

# install stoplight/prism
RUN npm install -g @stoplight/prism-cli

CMD ["prism", "mock", ${OpenAPI Spec Yaml}, "-h", "0.0.0.0", "-p", "8080"]

EXPOSE 8080

GitHub Actions

GitHub PagesにReDocを配置、Mock Server(Prism)をCloud RunへデプロイするGitHub Actionsを書きます。

name: Build and Push Image

on: [push]

jobs:
  build-and-publish:
    name: Build and Push Docker Image
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v2
        with:
          ref: ${{ github.ref }}
      - name: Node setup
        uses: actions/setup-node@v2
        with:
          node-version: 16
          cache: yarn
      - name: Yarn install
        run: |
          yarn install
      - name: Yarn build:doc
        run: |
          yarn build:doc
      - name: Redoc Deploy
        uses: peaceiris/actions-gh-pages@v3
        if: ${{ github.ref == 'refs/heads/main' }}
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: ./docs
      - name: Setup Google Cloud
        uses: google-github-actions/setup-gcloud@v0
        with:
          service_account_key: ${{ secrets.GCLOUD_AUTH }}
          project_id: ${{ secrets.GCLOUD_PROJECT_ID }}
      - name: Configure docker for artifact registry
        run: |
          gcloud auth configure-docker asia-northeast1-docker.pkg.dev
      - name: Set TAG
        run: |
          echo "TAG=$(npx -c 'echo "$npm_package_version"')" >> $GITHUB_ENV
      - name: Docker Build
        run: |
          docker build -t asia-northeast1-docker.pkg.dev/${{ secrets.GCLOUD_PROJECT_ID }}/prism/prism-image:${{ env.TAG }} ./
      - name: Docker Push
        run: |
          docker push asia-northeast1-docker.pkg.dev/${{ secrets.GCLOUD_PROJECT_ID }}/prism/prism-image:${{ env.TAG }}
      - name: Deploy to Cloud Run
        uses: google-github-actions/deploy-cloudrun@v0
        with:
          service: prism-server
          image: asia-northeast1-docker.pkg.dev/${{ secrets.GCLOUD_PROJECT_ID }}/prism/prism-image:${{ env.TAG }}
          region: asia-northeast1
      - name: Public Access Cloud Run
        run: |
          gcloud run services add-iam-policy-binding prism-server \
            --member="allUsers" \
            --region="asia-northeast1" \
            --role="roles/run.invoker"

上から説明していきます。

  1. 一旦、 push されるとGitHub Actionsが起動する仕組みにしています。

  2. Node setupにて、 Node.jsの環境を用意します。

  3. Yarn build:docにて、 redoc-cli bundle ${OpenAPI Spec Yaml} -o docs/index.html を実行しています。

  4. Redoc Deployでは、 peaceiris/actions-gh-pagesを使って、静的HTMLのReDocファイルをGitHub Pagesへデプロイしています。デフォルトだと、 gh-pages ブランチを作って、そこに ./docs フォルダの中身をデプロイします。

  5. Setup Google Cloud から、Google Cloudのセットアップです。(事前にGCPへアクセスできるサービスアカウントの設定やトークンをGitHub Secretsへ登録する必要があります)
    Cloud Runへデプロイするためには、以下作業をしなくてはなりません。

    1. Dockerイメージを作成
    2. DockerイメージをArtifact Registry(旧:Container Registry)へ格納
    3. Artifact RegistryからCloud Runを起動

    このあたりは Terraform を使ったほうが便利かと思ったのですが、 Terraform を使う場合、Cloud Build等でDockerイメージをビルドする必要があり、だったらGitHub Actions上でビルドした方が楽かなと思ったので、 Terraformの採用は止めました。(もし、違っていたら、ご教示頂けると助かります。)

  6. Configure docker for artifact registry にて、Artifact Registryの設定を行います。

  7. Set TAG で、Dockerイメージのタグを付与します。タグは package.json のバージョンにしました。

  8. Docker Build にて、Dockerイメージを作成。

  9. Docker Push にて、DockerイメージをArtifact RegistryへPush。

  10. Deploy to Cloud Run では、google-github-actions/deploy-cloudrunを使って、Dockerイメージを使ってCloud Runにデプロイ。

  11. 最後に Public Access Cloud Run で、Cloud Runへのアクセス制限をします。今回はアクセス制限せずに公開(allUsers に設定)

あとは、GitHubにソースをPushするだけで、ReDocの生成とCloud RunでMock Server(Prism)が動きます。

Cloud Runのアクセス制御について

今回は allUsers を使って、アクセス制限をかけずに公開しました。
しかし、用途によっては、アクセス制限が必要な場合があるので、その手段と個人的に感じたデメリットを以下に纏めます。

1) Cloud Load BalansingによるServerless NEGとCloud Armorを使った制限

Cloud Runの前に、Cloud Load BalansingのServerless NEGを置いて、Cloud Armorを使ってアクセス制限する方法。IPアドレスによる制限等が可能です。

  • デメリット

Cloud Load Balansingが高価。

2) Cloud Endpointによる制限

Cloud Runの前に、Cloud EndpointのESP(Extensible Service Proxy)を置くことで、なにかしらの認証(Google認証、Auth0を使用した認証、API Keyを使った認証など)を行った上でないとアクセスできないようにすることができます。

  • デメリット

ESPv2のDockerイメージ格納場所が、Artifact Registryに対応していない。(2022/04時点)
構築が少し大変。

3) Cloud RunのIAM(サービスアカウント)による制限

Cloud Runを起動できるIAM(サービスアカウントやGoogle Workspace)を用意してアクセスする。

  • デメリット

Authorizationヘッダーにトークンが必要になるので、トークン取得処理が別途必要。

まとめ

金銭的に余裕があるのであれば、Cloud Load BalansingによるServerless NEGとCloud Armorを使った制限をオススメします。
金銭的に余裕がなく、Cloud RunにアップしたMock Server(Prism)を使う人が少数なら、Cloud RunのIAM(サービスアカウント)による制限でも良いと思います。
ただし、Mock Server(Prism)を動かしたい人には、サービスアカウントの鍵情報を渡す必要がるので、注意が必要です。(自己責任でお願いしますm(_ _)m)
あと、トークンの取得が必要なので、以下ライブラリも必要になります。

APIを呼び出すコードのサンプルも置いておきます。

import { JWT } from "google-auth-library"
import service_account from '../${サービスアカウントの鍵}.json'
import axios from 'axios'

;(async () => {
  const client = new JWT({
    forceRefreshOnFailure: true,
    key: service_account.private_key,
    email: service_account.client_email,
  })

  const url = "${Cloud Runのエンドポイント}"
  const token = await client.fetchIdToken(url)
  const { data } = await axios.get(`${url}`, {
    headers: {
      Authorization: `Bearer ${token}`
    }
  })
  console.log(`data: ${JSON.stringify(data)}`)
})()

さいごに

OpenAPI Specを活用すれば、フロントとバックエンドでAPIの仕様が共有できます。
しかも、事前にこのようなCIを用意しておくことで、共有漏れを防げぐことができ、バックエンド側でAPIを用意できない間でもフロントエンドは手を止めなくて済みます。
とはいえ、実は私自身、これを実践で使ったことがありません😭
でも、こういったことは事前に考えておくことが重要なのだと思いました。🙂

3
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
3
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?