OpenAPIドキュメントから生成した静的ファイルをいい感じにホストしてみた
OpenAPIドキュメントから生成した静的ファイルをFirebase Hostingを使っていい感じにホストしてみました。この仕組みにより開発者は簡単に最新の定義にたどり着けるようになります。
概要は以下の通り
- GitHubにPushしたOpenAPIドキュメントを元にCloudBuildで静的ファイルを生成
- CloudBuildが生成したドキュメントをFirebase Hostingにデプロイ
- Cloud Functions for FirebaseでBasic認証
それぞれのサービスをAWSのサービスにマッピングするとFirebase HostingはAmplify Console、Cloud Functions for FirebaseはLambda@Edge、CloudBuildはCodeBuildのようなイメージになります。
それでは行ってみましょう!!
次の環境で検証します。
$ node -v v10.18.1
今回作成したコードは以下のリポジトリにあげています。
ローカルで静的ファイルを生成
まずはローカルでOpenAPIドキュメントから静的ファイルを生成できる状態にします。任意のディレクトリを作成後、
package.json
を生成し、redoc-cli
をインストールします。
$ yarn init $ yarn add redoc-cli
次にpackage.json
以下のように修正します。
"scripts": { "generate:app": "redoc-cli bundle docs/specs/app.yaml --output app.html" },
生成対象となるOpenAPIドキュメントを配置します。Stoplightなどを使うと簡単に作成できます。
openapi: 3.0.0 info: title: app version: 1.0 paths: /: get: summary: Hoge API responses: '200': description: ok content: application/json: schema: type: object properties: payload: type: object '400': description: Bad Request parameters: - schema: type: string in: header name: authorization required: true
redoc-cli
を実行しローカル上で静的ファイルが出力されたことを確認します。
$ yarn run generate:app $ open app.html
問題なさそうです。
Firebaseプロジェクトの設定
Firebaseプロジェクトの設定を行います。
Firebaseプロジェクト作成
今回はCloudBuildから`FIREBASE_TOKEN`を指定せずにFirebaseにデプロイします。FirebaseのプランはSpark(無料)から Blazeになるので注意してください。
GCPのコンソールからFirebaseHosting
を選択し、内容を確認の上プロジェクトを作成します。作成完了後はこのような表示となります。
Firebaseプロジェクト初期処理
ホスティングされたコンテンツにBasic認証をかけるための設定を追加します。
firebaseコマンドをインストールします。firebaseにログインしプロジェクトを確認します。
$ firebase login $ firebase projects:list ✔ Preparing the list of your Firebase projects ┌──────────────────────────┬───────────────────────────┬──────────────────────┐ │ Project Display Name │ Project ID │ Resource Location ID │ ├──────────────────────────┼───────────────────────────┼──────────────────────┤ │ XXXXXXXXXXXXXXXXXXXXXXXX │ XXXXXXXXXXXXXXXXXXXXXXXX │ asia-northeast1 │ └──────────────────────────┴───────────────────────────┴──────────────────────┘
firebase init
を実行しfirebaseのコンフィグファイルを作成します。Functions、Hostingの2つを有効にします。
$ firebase init ######## #### ######## ######## ######## ### ###### ######## ## ## ## ## ## ## ## ## ## ## ## ###### ## ######## ###### ######## ######### ###### ###### ## ## ## ## ## ## ## ## ## ## ## ## #### ## ## ######## ######## ## ## ###### ######## You're about to initialize a Firebase project in this directory: ? Which Firebase CLI features do you want to set up for this folder? Press Space to select features, then Enter to confi rm your choices. ◯ Database: Deploy Firebase Realtime Database Rules ◯ Firestore: Deploy rules and create indexes for Firestore ◉ Functions: Configure and deploy Cloud Functions ❯◉ Hosting: Configure and deploy Firebase Hosting sites ◯ Storage: Deploy Cloud Storage security rules ◯ Emulators: Set up local emulators for Firebase features
先ほど作成したプロジェクトを選択します。
=== Project Setup First, let's associate this project directory with a Firebase project. You can create multiple project aliases by running firebase use --add, but for now we'll just set up a default project. ? Please select an option: (Use arrow keys) ❯ Use an existing project Create a new project Add Firebase to an existing Google Cloud Platform project Don't set up a default project
Cloud Functionsの言語はJavaScriptとします。
=== Functions Setup A functions directory will be created in your project with a Node.js package pre-configured. Functions can be deployed with firebase deploy. ? What language would you like to use to write Cloud Functions? ❯ JavaScript TypeScript
その他項目は一旦デフォルトで構いません。処理が完了するとfirebaseのコンフィグファイルが作成されます。
FirebaseHostingサイト追加
Firebase Hostingのサイト追加します。 私の環境では既にサイトが存在したいるため、「別サイトの追加」より追加していきます。
複数サイトを管理する場合は、firebase.json
にsiteを追加します。
{ "hosting": { "site": "blog-jogan", "public": "public", "ignore": [ "firebase.json", "**/.*", "**/node_modules/**" ] } }
Cloud Functions for Firebaseの作成
ここからCloud Functionsの設定を追加していきます。
まずは、public配下の不要なファイルを削除します。フォルダ自体は必要なため.gitkeep
を配置しておきましょう。
$ rm -rf ./public/* $ touch ./public/.gitkeep
Basic認証を実施するための処理を実装します。functions/index.js
を以下のように修正します。
const functions = require('firebase-functions') const express = require('express') const basicAuth = require('basic-auth-connect') const app = express() app.all('/*', basicAuth(function(user, password) { return user === 'hoge-user' && password === `${functions.config().user.password}`; })); app.use(express.static(__dirname + '/static/')) exports.app = functions.https.onRequest(app)
これで当該ファンクションに到達した全てのリクエストはbasic認証を通るようになり、認証に成功したユーザーのみstaticフォルダにアクセスできるようになります。
パスワードの情報はGitHubにはコミットしたくないので、ファンクションから読み込み可能な環境変数に値をセットします。
$ firebase functions:config:set user.password=<password>
functions/package.json
のengines
のバージョンを10に変更します。
"engines": { "node": "10" },
functions
配下に移動しCloud Functionsが必要なモジュールをインストールします。
$ cd functions $ yarn add express $ yarn add basic-auth-connect
ホストしたサイトへのリクエストは、上記のファンクション経由となるようfirebase.json
にrewrites
を属性を追加します。
{ "hosting": { "site": "blog-jogan", "public": "public", "ignore": [ "firebase.json", "**/.*", "**/node_modules/**" ], "rewrites": [ { "source": "**", "function": "app" } ] } }
CloudBuildの設定
CloudBuildの設定を行います。
まずはCloudBuildから起動するfirebaseコマンドが内包されたコンテナを用意します。任意のディレクトリで以下を実行してください。
$ git clone https://github.com/GoogleCloudPlatform/cloud-builders-community.git $ cd cloud-builders-community/firebase $ gcloud builds submit --project <project name> --config cloudbuild.yaml .
これによりfirebaseコマンドが内包されたコンテナがGCRにPushされます。
次にCloudBuildから実行するスクリプトを定義します。package.json
を以下のように修正します。
- CloudFunctionsのモジュールをインストールするための
functions:install
を追加 generate:app(redoc-cli bundle)
の出力先をfunctions/static/app.html
に変更
"scripts": { "functions:install": "cd functions && yarn install", "generate:app": "redoc-cli bundle docs/specs/app.yaml --output functions/static/app.html" },
CloudBuildでstep実行する処理を定義します。この定義がCloudBuildにより実行されると、必要なモジュールのインストール、静的ファイルの生成、firebaseへのデプロイが行われます。
steps: - name: node:10.18 entrypoint: yarn args: ['install'] - name: node:10.18 entrypoint: yarn args: ['functions:install'] - name: node:10.18 entrypoint: yarn args: ['generate:app'] - name: 'gcr.io/$PROJECT_ID/firebase' args: ['deploy', '--project', $PROJECT_ID]
最後にCloud BuildからFirebase Hosting、Functionsへデプロイするための権限を付与します。サービスアカウント権限から CloudFunction開発者とFirebase管理者を有効にしましょう。
CloudBuildトリガー設定
CloudBuildのトリガーを設定します。
CloudBuildからトリガーを選択し、リポジトリの接続をクリックします。
ソースをGitHubとした後、指定のリポジトリに接続します。
一旦、この状態でトリガーを作成します。
masterへのPushのみ発火するようにトリガーを編集します。
正規表現を^master$
に変更し保存します。
自動デプロイ
githubにコードをPushします。リポジトリは適宜読み替えてください。
$ git add . $ git commit -m "first commit" $ git remote add origin https://github.com/jogannaoki/openapi-firebase-hosting.git $ git push -u origin master
すると、Cloud Buildが自動実行されます。
処理が完了すると、Basic認証のある静的サイトが出来上がります。
うまくホストできました。
さいごに
OpenAPIドキュメントから生成した静的ファイルをFirebase Hostingを使っていい感じにホストしてみました。APIの定義を簡単に開発者に共有できるのはかなり嬉しいのではないでしょうか。どなたかの参考になれば幸いです。 ※Amplify Consoleでも同じようなことはできます。