しばやん雑記

Azure Serverless とメイドさんが大好きなフリーランスのプログラマーのブログ

Azure Static Web Apps で API 統合を使った際の開発・運用のベストプラクティス

先日 Static Web Apps に Azure Functions 以外の API を簡単に持ち込める機能が追加されました。App Service / Container Apps / API Management の 3 つを追加で持ち込めるようになったので、API が多いアプリケーションも Static Web Apps でホストしやすくなりました。

Azure 上にデプロイしてしまえば非常に確認は簡単なのですが、ローカルでの開発中にはどのように扱うのが最適なのか気になったので検討しました。

結論としては Static Web Apps CLI を使えば全て解決するという話なのですが、API 統合を使うと一部の機能が使えなくなるので、そのあたりの代替方法含めて確認しました。

SWA CLI を使って API 統合付きで開発する

Static Web Apps の特徴である API 統合と認証をローカル開発環境でも再現するための SWA CLI ですが、これを使えば Azure Functions 以外の API も簡単に扱えるようになります。

公式ドキュメントのローカル開発環境についても参考になりますが、まだ Azure Functions 専用になっているので App Service で API を用意する際には肝心な部分が書いていません。

SWA CLI には任意の URL に API リクエストをプロキシする機能があるので、この設定を使うことで Azure Functions 以外も使えるようになります。具体的には --api-devserver-url というオプションですが、起動コマンドが長くなってしまうので SWA CLI の設定ファイルを作成してしまうのがお勧めです。

設定ファイルの Boilerplate は swa init を実行すれば生成できます。

SWA CLI の設定ファイルで apiLocationapiDevserverUrl を指定すると、Azure Functions 以外の API へプロキシすることが可能になります。稀に apiLocation に URL を指定する例を出てきますが、その場合は Azure Functions として扱われてしまい Core Tools のインストールが始まってしまいます。

開発中は apiDevserverUrlappDevserverUrl を指定する方法が既存ツールも使えるので良いです。

{
  "$schema": "https://aka.ms/azure/static-web-apps-cli/schema",
  "configurations": {
    "swa-byoa-test": {
      "apiLocation": "api",
      "appLocation": "app",
      "outputLocation": "blog/.vuepress/dist",
      "appBuildCommand": "npm run build",
      "run": "npm run dev",
      "apiDevserverUrl": "http://localhost:5262",
      "appDevserverUrl": "http://localhost:8080"
    }
  }
}

今回はバックエンドの API を ASP.NET Core Web API で用意しているので、API サーバーを起動するには dotnet watch を使います。Hot Reload がある程度効くのでフロント側との相性が良いはずです。

API サーバーの起動を行えば、後は swa startswa-cli.config.json が保存されたパスで実行すると、SWA エミュレータが起動してアクセス出来るようになります。

これでフロントエンドとバックエンドの両方が Hot Reload 有効な状態で開発が行えるようになりました。理想的には swa start で API サーバー側も起動したいですが、それは難しそうでした。

その代わりに VS Code 側でデバッグ用の設定ファイルを用意すれば、デバッガーをアタッチ済みの状態で API サーバーを起動できるので API 側のデバッグは比較的やりやすいです。

ブランチ・名前付きプレビュー環境を利用する

Static Web Apps で API 統合を利用すると Pull Request のプレビュー環境は使えなくなりますが、代わりにブランチ・名前付きプレビュー環境は API 統合の設定を行えば使えるので、こちらを利用する形になります。

Pull Request のプレビュー環境ですが、現実的には完全な静的サイトもしくは Managed Functions を使う時ぐらいしか動作しないので、API 統合を使う際には Codespaces でサクッと確認できる環境を作れるようにしておいた方が安心です。

Codespaces は Pull Request に紐づいた環境を以下のように簡単に作れるようになっています。

あえて Static Web Apps の Pull Request に関連する Workflow 定義を削除することで、Pull Request 環境が作成されなくなります。ARM レベルでは設定もあるみたいですが、ドキュメント化されていなさそうです。

API 側のプレビュー環境については、現在 SWA に Deployment Slot や Container Revision を登録できないので、専用の App Service や Container App を作成する必要があります。

Dev Container / Codespaces で確認出来るようにする

Pull Request の確認やローカル開発環境の統一のために、VS Code の Dev Container や GitHub Codespaces を利用できるようにしておくと、開発がかなり捗るようになります。

Dev Container の定義ファイルは VS Code から利用しているプラットフォーム向けに追加すれば良いですが、SWA CLI を使うために Node.js は必ずインストールするようにしておきましょう。最近は定義ファイル作成時に Node.js が必要かを聞いてくれるはずです。

{
	"name": "C# (.NET)",
	"build": {
		"dockerfile": "Dockerfile",
		"args": { 
			// Update 'VARIANT' to pick a .NET Core version: 3.1, 6.0
			// Append -bullseye or -focal to pin to an OS version.
			"VARIANT": "6.0-bullseye",
			// Options
			"NODE_VERSION": "16"
		}
	},

	// Configure tool-specific properties.
	"customizations": {
		// Configure properties specific to VS Code.
		"vscode": {	
			// Add the IDs of extensions you want installed when the container is created.
			"extensions": [
				"ms-dotnettools.csharp"
			]
		}
	},

	// Use 'postCreateCommand' to run commands after the container is created.
	"postCreateCommand": "npm install -g @azure/static-web-apps-cli",

	// Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
	"remoteUser": "vscode",
	"features": {
		"docker-in-docker": "latest"
	}
}

今回は .NET 6 向けの定義を作成して、SWA CLI のインストールを postCreateCommand に追加することで Codespaces が起動したらすぐに swa start の実行が出来るようにしました。

実際に Codespaces 上で .NET 6 のバックエンド API を立ち上げつつ、SWA CLI のプロキシ機能でアクセス出来ていることが確認出来ます。起動を F5 で出来るようにしても良さそうです。

このように PR プレビュー環境については Codespaces で十分補えるのではないかと考えています。問題となりがちなシークレットについても Codespaces の場合は安全に共有できるのがメリットです。

Front Door を導入する際の注意点

Static Web Apps で API 統合が必要な規模のアプリケーションでは、殆どのケースで Front Door を前段に入れてキャッシュや圧縮を行って表示パフォーマンス改善を図りたいと思います。

現在は標準で Static Web Apps が Front Door に対応しているので、以前書いたエントリや公式ドキュメントを参照してもらえれば設定自体は簡単に行えるかと思います。

重要なのは Static Web Apps へのアクセス元を Front Door に制限することと、認証に関係するエントリポイントはキャッシュの対象外にすることです。

もちろん API も例外ではなく、以下のように Rule Set を作成して API へのアクセスはキャッシュを無効化しておかないと、予期せぬ結果となる可能性があります。

設定が面倒な場合は Enterprise-grade Edge を有効化してしまう手もありますが、カスタマイズの余地がほぼ無いため Front Door を自前で入れるほうが個人的には好きです。

複雑なルールが必要なくて、単純な CDN として必要なケースは Enterprise-grade Edge で良さそうです。