Azure Static Web Apps × Azure Functionsで動的Webアプリを無料で立ち上げる

# はじめに
こちらは[慶應義塾大学理工学部のアドベントカレンダー](https://adventar.org/calendars/7773)23日目の記事です。

`Azure Static Web Apps`や`Azure Functions`の名前は前から知ってるし、便利なのも知ってるけどお金結構かかりそうだな、という偏見もあり中々使う機会がありませんでしたが、仕事で使う必要が出てきたので色々と調べていたところ、簡単なアプリなら無料で作れることがわかりました。そこで自分の勉強のためにも、今回は静的なWebアプリを構築できる`Azure Static Web Apps`と`Azure Functions`を利用して、動的Webサンプルアプリのサンプルとしてオリジナル個人ブログを作ってみようと思います。

# Azure Static Web Appsとは
`Azure Static Web Apps`とは静的なWebアプリをホスティングするサービスです。後で紹介する`Azure Functions`と組み合わせることで、簡単な動的Webアプリを作ることができます。

:::note info
静的Webアプリとは既に作成されているページを表示するWebアプリのことを指し、動的Webアプリとはアクセスごとにページを作成して表示するWebアプリのことを言います。
:::


https://azure.microsoft.com/ja-jp/products/app-service/static/#features

似たようなサービスで、`App Service`というものがありますが、こちらはサーバランタイムが必要な動的なWebアプリを作成したい場合に向いていています。しかし、本記事のように簡単な動的Webアプリであれば`Azure Static Web Apps` × `Azure Functions`でも構築することが可能です。

https://azure.microsoft.com/ja-jp/products/app-service/#overview

## Azure Static Web Appsの料金
2022年12月現在の`Azure Static Web Apps`の料金です(1 USD = 138.795 JPY)。今回のように簡単なアプリであればFreeプランで利用することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2452857/876ab5cd-f687-dff5-c5e2-8f6de5d651db.png)

https://azure.microsoft.com/ja-jp/pricing/details/app-service/static/

# Azure Functionsとは
`Azure Functions`とはサーバーレスで定義済みの関数を実行することができるソリューションです。`Azure Functions`の関数は`C#`、`Java`、`JavaScript`、`PowerShell`、`Python`のいずれかを使って記述することができます。

:::note info
サーバーレスとはファイルのアップロード、データベースの変更、スケジューリングによる実行などイベントが発生したときだけ処理を実行する仕組みであり、通常のサーバーのように常に稼働させていく必要はなく、必要な時のみ利用することができるためサーバー代のコストカットを期待できます。
:::

https://azure.microsoft.com/ja-jp/products/functions/#overview

## Azure Functionsの料金
こちらの表は2022年12月現在の`Azure Functions`の料金です(1 USD = 138.795 JPY)。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2452857/856527d9-c841-9806-8f2c-639fb8104702.png)
表によると、Freeプランでも1か月あたり40 万GB秒の実行時間と100 万回の実行を行うことができます。100 万回という実行回数は、30 秒に1 回の頻度で1か月処理を実行し続けることが可能なため、今回のサンプルアプリでは十分な実行回数になります。

:::note info
GB秒の単位の意味は、関数が実行される秒と消費メモリ量を掛け合わせた単位です。例えば、1 回の実行に1 秒と1 GBのメモリが必要な関数を1 回実行したとすると、その関数によるサーバーの使用時間は1 GB秒になります。
:::

# 動的Webアプリの作成フロー
今回のWebアプリは次のような流れで作成します。
1. [VSCode拡張機能のインストール](#1-vscode拡張機能のインストール)
2. [GitHubリポジトリの作成](#2-githubリポジトリの作成)
3. [Webページの公開](#3-webページの公開)
4. [APIの作成と連携](#4-apiの作成と連携)

## 1. VSCode拡張機能のインストール
Webアプリを作成する下準備として、まずはVSCodeの拡張機能を2つインストールしましょう。

### ①Azure Static Web Apps
左にあるアクティビティバーから拡張機能のロゴを選択し、`Azure Static Web Apps`と入力すると、次の画像のような拡張機能が見つかるのでインストールしてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2452857/057c0820-a343-0d15-a284-7f2372bfd13c.png)

### ②Azure Functions
また、同様にして`Azure Functions`の拡張機能もインストールしておきましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2452857/48b4b148-ebdf-16bb-4bcb-502a65d71ce0.png)

## 2. GitHubリポジトリの作成
次にリモートリポジトリを作りましょう。今回はリポジトリ名を`SampleAzureStaticWebApps`としました。リポジトリ名を入力した後、`Create repository`のボタンを押せば作成完了です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2452857/4ada6b7e-87c7-75b1-8ba3-a2eab3b3e57b.png)
リポジトリを作成した後、次のような画面が表示されるので、`creating a new file`を押して次のような`index.html`ファイルをコミットしましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2452857/41e43101-99e0-6314-fd6c-ab4f31b10739.png)
```index.html
hello world
```
最後に、`index.html`をローカルにクローンして下準備完了です。
```terminal
C:\Users\yus\SampleApp> git init
C:\Users\yus\SampleApp> git clone https://github.com/yus04/SampleAzureStaticWebApps.git
```

## 3. Webページの公開
次に`Azure Static Web Apps`を使って、先ほど作成した`index.html`を表示するWebページを公開しましょう。`Ctrl` + `P`でコマンドパレットを開いた後、`>create Static Web App`と入力して表示された`>Azure Static Web Apps: Create Static Web App...`を実行します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2452857/70596ea3-9320-f68f-fd74-4ca76016da40.png)
すると、Azureにサインインするように求められるので`Sign in to Azure...`を選びます。(アカウントを持っていない場合は`Create an Azure Account...`を選択します。)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2452857/f00d8ff0-1240-be33-ba99-af381cbab521.png)
次にサブスクリプションを聞かれるので、使うサブスクリプションを選びます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2452857/aaec2cc3-f4d0-950d-6330-05e3f28f3787.png)
アプリの名前を聞かれるので、自分で決めたアプリの名前を入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2452857/3916572e-e04a-aa99-102f-b3b566d15621.png)
`Azure Functions`のリージョンを選びます。私は`East Asia`を選びました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2452857/320c2b18-e689-de67-d3c7-c20645527b0f.png)
使いたいフレームワークを選びます。私は`React`を選択しましたが、何を選んでも大丈夫です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2452857/1fc52cdf-e382-72b8-65b4-44a70d1dcad1.png)
アプリの場所を決めます。デフォルトのままでよいです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2452857/125e7c9c-380c-19ea-d231-991d1dbd94fa.png)
ビルドファイルの場所を決めます。こちらもデフォルトのままでよいです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2452857/04c3760f-d99a-376b-3da0-9ebdcb1db148.png)
無事にアプリの作成を完了したら、アクティビティバーからAzureのロゴを選択し、表示されたファイルツリーの中から`Static Web Apps`をクリックします。展開されたフォルダの中に先ほど作成したアプリ(この画像の場合では`SampleAzureStaticWebApps`)を右クリックし、`Browse Site`を押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2452857/71f602a4-63d7-6a2d-af6d-42c086002803.png)
`index.html`の中身が表示されれば静的Webページの出来上がりです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2452857/efe6e682-e1a6-c0c7-9bb2-1f8069b79643.png)

## 4. APIの作成と連携
ここまでのところで、`hello world`を表示する静的Webページができました。なので、最後に`Azure Functions`を使って動的アプリにしましょう。`Ctrl` + `P`でコマンドパレットを開き、`>create Http Function`と入力して表示された`Azure Static Web Apps: Create HTTP Function...`を実行します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2452857/13e5421e-36bf-4acd-e653-17ccd5d88fa7.png)
するとAPIで使うプログラミング言語を聞かれます。ここではJavaScriptを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2452857/c90b2b3f-0dbe-5ef5-5110-a85a5b99ef70.png)
APIの名前を聞かれます。今回はデフォルトの関数名を使います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2452857/26366060-926f-fcd7-68ca-d13dc02afca2.png)
そうすると以下のように、先ほど選択した言語で関数を作ってくれます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2452857/4dfbc640-aa35-187e-dbbc-16277288e8e6.png)
ここで、`index.html`と`index.js`を次のように書き換えます。
```index.html
<b id="res">...</b>

<script>
(async function() {
    const { time } = await( await fetch(`/api/HttpTrigger1`)).json();
    document.querySelector('#res').textContent = time;
}());
</script>
```

```index.js
module.exports = async function (context) {
    context.res.json({
        time: get_time()
    });
};

function get_time(){
    var now = new Date();
    var year = now.getFullYear();
    var month = now.getMonth()+1;
    var date = now.getDate();
    var hour = now.getHours();
    var minute = now.getMinutes();
    return (
        year + "/" + 
        month + "/" +
        date + " " +
        hour + ":" +
        minute
    );
}
```
:::note info
`context`とは、エクスポートされる関数の最初の引数です。バインディングデータの送受信、ログ記録、ランタイムとの通信に使用に使用されます。
:::


変更をpushします。
```terminal
C:\Users\yus\SampleApp> git add .
C:\Users\yus\SampleApp> git commit -m ""
C:\Users\yus\SampleApp> git push origin master
```
再び、アプリをブラウジングしてグリニッジ標準時(GMT)が表示されれば`Azure Functions`が無事に機能していることを確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2452857/af32749d-702b-df2a-822f-6985b5db4eff.png)

:::note warn
GitHub Actionsのビルドとデプロイに時間がかかるため、コミットの変更が反映されるまで少し時間がかかる場合があります。以下のスクリーンショットの通り、GitHub Actionsのコミットにチェックマーク✅が付けば、コミットの変更が反映されたことになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2452857/491df332-82d4-a0c1-e431-fc9c6c196ae6.png)
:::

# おわりに
今回は`Azure Static Web Apps`と`Azure Functions`を使って簡単な動的Webアプリを作ることができました。Webアプリを公開する際に面倒なビルドやデプロイは`GitHub Actions`を使って自動化されているため、快適に開発することができました。ポートフォリオや簡単なコーポレートサイトであれば、今回のやり方でも十分に作れると思いました。