Azure Static Wab Apps で Data API を使用する

# 前提
- Azure SQL Database のデータに、REST-API でアクセスするためだけに Static Web Apps を使用する話です。ダイナミックなWebサイトを作る話ではないです。
- 認証・認可は考慮せず、誰でもどこからでもアクセスできるザル設定です。
- アカウント: Azureアカウントの他に、GitHubアカウント、または Azure DevOps アカウントが必要になります。 この記事では GitHub を使用します。
- 表記の揺れが残っていますがご容赦ください。

# 手順のサマリー
1. Azure Resource Group を作成
1. Azure SQL Server を作成
1. Azure SQL Database を作成
1. GitHub リポジトリ を作成
1. GitHub リポジトリ に構成ファイルを作成
1. Azure Static Web Apps を作成
1. Azure Static Web Apps をデータベースに接続
1. 動作確認

# リソース名のサマリー
今回はAzure、GitHub上に以下のリソース等を作成します。
|リソース等|名前|備考|
|:---|:---|:---|
| Azure Resource Group | swada-rg |
| Azure SQL Server | swada-sqlsrv |
| Azure SQL Database | swada-db |
| Azure Static Web Apps | swada-web |
| GitHub Repository | swada-github-repos |

# 1. Azure Resource Group を作成
これから作成する SQL Database などのリソースを束ねるグループです。 管理上のグループなので運用に合わせて作ればよいですが、今回作るリソースを一つのリソースグループに束ねることにしました。
Azure Portal から 「リソース グループ」 を作成します。 入力内容は以下の通りです。
|項目|設定値|備考|
|:---|:---|:---|
| サブスクリプション | 私のサブスク |
| リソースグループ | swada-rg | 検証用の名前。運用に合わせてお好みで。 |
| リージョン | Japan East | East/Westはお好みで |

# 2. Azure SQL Server を作成
Azure Portal から「SQL Server (logical server)」を作成します。 入力内容は以下の通りです。
|項目|設定値|備考|
|:---|:---|:---|
| サブスクリプション | 私のサブスク |
| リソースグループ | swada-rg |
| サーバー名 | swada-sqlsrv |
| 場所 | Japan East | East/Westはお好みで |
| 認証方法 | SQL 認証を使用する |
| サーバー管理者ログインの入力 | db-kanri-sha |
| パスワード |  |
| パスワードの確認 |  |
| Azure サービスおよびリソースに<br>このサーバーへのアクセスを許可する | はい |
| Microsoft Defender for SQL を有効にする | 後で |


# 3. Azure SQL Database を作成
Azure Portal から「SQL Database」を作成します。 入力内容は以下の通りです。
|項目|設定値|備考|
|:---|:---|:---|
| Want to try Azure SQL Database for free? ... | Apply offer | 先のようなオファーが表示されていたら。CPU時間、データ量を制限することで無償利用になる。 | 
| サブスクリプション | 私のサブスク |
| リソースグループ | swada-rg |
| データベース名 | swada-db |
| データベースサーバー名 | swada-sqlsrv | 先程作ったやつ |
| SQL エラスティック プールの使用 | いいえ | 検証目的なので考慮せず |
| ワークロード環境 | 開発 |
| コンピューティングとストレージ | 規定のまま | 検証目的なので |
| バックアップ ストレージの冗長性 | ローカル冗長 | 検証目的なので考慮せず |
| Azure サービスおよびリソースに<br>このサーバーへのアクセスを許可する | はい |
| 現在のクライアント IP アドレスを追加する | はい | ローカルPCで Data Studio 等を使う場合は必要。 |
| プライベート エンドポイント | 作成しない | 今回は必要ない |
| 接続ポリシー | 既定 | Azure内接続:リダイレクト接続 / Azure外接続:プロキシ接続 |
| 暗号化接続 | TLS 1.2 |
| Microsoft Defender for SQL を有効にする | 後で |
| 台帳 | (何もしない) | 検証目的で省略 |
| Server identity | (何もしない) | 検証目的で省略 |
| Database level key | (何もしない) | 検証目的で省略 |
| Enable secure enclaves | いいえ | 検証目的で省略 |
| 既存のデータを使用します | サンプル | 検証用にデータが入ったテーブルが欲しいのでサンプルを選択。 |
| 照合順序 | Japanese_CS_AS_KS_WS | お好みで |

# 4. GitHub リポジトリ を作成
Static Web Apps にデプロイするコンテンツファイルのリポジトリをGitHubに作成します。DevOpsでも良いです。 Static Web Apps を作成するときに、構成ファイルやコンテンツが格納された GitHub または DevOps リポジトリを求められます。
|項目|設定値|備考|
|:---|:---|:---|
| アカウント | 自分のGitHubアカウント |
| リポジトリ | swada-github-repos | 説明のためにくどい名前にしています。 |
| ブランチ | main |

# 5. GitHub リポジトリ に構成ファイルを作成
　Data API だけを使う範囲ではconfigファイルだけあれば良く、HTML等のWebコンテンツは不要です。とは言え、Static Web Apps の作成が成功した事を確認するために index.html ぐらいは作っておくことにします。

- フォルダー階層とファイル (リポジトリのルート)
```
/
├── index.html
├── staticwebapp.config.json  (Static Web Apps 構成ファイル)
└── swa-db-connections/
    └─ staticwebapp.database.config.json   (Database接続 構成ファイル)
```

## **index.html**
  Static Web Apps が正常にデプロイされたことを確認するために HTMLコンテンツ を用意しました。 無くても Data API は使用できます。
```index.html
<html>
  <head><title>Static Web Apps - Data API - Trial</title></head>
  <body><div>Static Web Apps - Data API - Trial</div></body>
</html>
```

## **staticwebapp.config.json**
Static Web Apps の構成ファイルです。 今回は無くても構わないのですが IP制御 だけ参考掲載します。また判った事もあるのでTipsとして掲載します。
- Static Web Apps をしっかり運用するなら諸々設定が必要です。
- configファイルなしでは誰でもアクセスできる公開アプリになります。
- アクセス制御したい場合は configファイル に 認証・認可・IP制限 等の設定が必要です。
- ただし、認証・認可・IP制限の設定は Freeプラン では無視されます。
- そのため、しっかりアクセス制御する場合は Standardプラン が必要です。

```staticwebapp.config.json
{
    "networking": {
        "allowedIpRanges": [
            "aaa.bbb.ccc.ddd/32"
        ]
    }
}
```
## **staticwebapp.database.config.json**
Static Web Apps を SQL Database に接続してテーブル等を API として公開するための構成ファイルです。
- "connection-string": でデータベースへの接続文字列を定義しています。
- なのですが、Azure上の Static Web Apps では、Azure Portal からの登録した接続設定で上書きされので、修正は不要です。
- 自分のPC等のローカルな開発環境に Static Web Apps を構築した場合は正しい接続文字列が必要になりますが、その際はconfigに直接記述せず、環境変数 DATABASE_CONNECTION_STRING に接続文字列を設定しておく使い方になります。(.envなどを使用)
- "runtime": の設定も深堀したいですがいったんこのまま使います。
- 公開するテーブル等のデータベースオブジェクトは "entities": で指定します。
- URLのパスに公開する名前、実際のデータベースオブジェクト名、許可する操作(読取・更新等)、許可するロール を指定します。
- 下記のサンプルでは、データベース上のテーブル "SalesLT.Product" を "prod" の名前でURLに公開しています。
- 複数のデータベースオブジェクトを定義する場合は、entiries:{ } 内で定義を繰り返します。
- 実行可能な操作は、actions: で定義します。下記サンプルでは CRUD 全てが許可されていますが、読取だけに制限するには "read" のみを記載します。
- この操作を許可するロールを "role": に指定する事で一定のアクセス制御(認可)ができます。
- 下記 config では、"role": "anonymous" なので、誰でも操作できるので、アクセス制限する場合は適切なロール名を指定します。
- とは言え、そもそも Standardプランにして認証設定が必要ではありますが。

```swa-db-connections/staticwebapp.database.config.json
{
    "$schema": "https://github.com/Azure/data-api-builder/releases/latest/download/dab.draft.schema.json",
    "data-source": {
        "database-type": "mssql",
        "options": {
        "set-session-context": false 
        },
       "connection-string": "@env('DATABASE_CONNECTION_STRING')"
    },
    "runtime": {
        "rest": {
        "enabled": true,
        "path": "/rest"
        },
        "graphql": {
        "allow-introspection": true,
        "enabled": true,
        "path": "/graphql"
        },
        "host": {
        "mode": "Development",
        "cors": {
            "origins": ["http://localhost:4280"],
            "allow-credentials": false
        },
        "authentication": {
            "provider": "StaticWebApps"
        }
        }
    },
    "entities": {
        "prod": {
        "source": "SalesLT.Product",
        "permissions": [
            {
                "actions": ["create", "read", "update", "delete"],
                "role": "anonymous"
            }
        ]
        }
    }
}
```
以上を作成したらリポジトリにコミット・同期しておきます。
Static Web Apps を作成する際に、Azure 側から読み取られます。

# 6. Azure Static Web Apps を作成
|項目|設定値|備考|
|:---|:---|:---|
| サブスクリプション | 私のサブスク |
| リソースグループ | swada-rg |
| 名前 | swada-web |
| プランの種類 | Free | Freeは認証・認可が使えないがお試しということで。 |
| Azure Functions APIとステージングのリージョン | East Asia |
| ソース | GitHub
| GitHub アカウント | 自分のGitHubアカウント | GitHubにサインインして Static Web Apps からのアクセスを承認します。 |
| 組織 | 自分のGitHubアカウント |
| リポジトリ | swada-github-repos | 先程作ったGitHubリポジトリをプルダウンで選択。 |
| 分岐 | main | カタカナで言うところの ブランチ を指定。 |

リソースが作成されたら概要ページに移動します。
右上にアクセスするための URL があるので控えておきます。 後で curl でAPIを叩いてテストします。
リンクをクリックして Webページ が表示されることを確認してください。
|項目|設定値|備考|
|:---|:---|:---|
| URL | https://{生成されたホスト名}.azurestaticapps.net |

Tips
- 作成プロセスが開始すると、GitHubリポジトリからconfigファイル等が Azure内 コピーされます。 (正確にはクローンなのだろうか)
- cnofigファイルを書き換えた場合は、GitHubリポジトリにコミットされれば、CI/CDワークフローで自動的に Azure上の Static Web Apps に反映されます。
- そのワークフローの実行状況は、GitHubリポジトリ(Webサイト画面)の Action タブで確認できます。

# 7. Azure Static Web Apps をデータベースに接続
1. Static Web Apps リソース swada-web のページに移動します。 
2. 左側ペインで データベース接続(プレビュー) ページを開きます。 
3. 運用セクションの一覧に、環境名 Development の行があり、右端に 「既存のデータベースのリンク」 があるのでクリックします。
4. ここで接続するデータベースを指定して登録します。

|項目|設定値|備考|
|:---|:---|:---|
| データベースの種類 | Azure SQL Database |
| サブスクリプション | 私のサブスク | 
| リソース グループ | swada-rg |
| リソース名 | swada-sqlsrv | SQL Server を指定 |
| データベース名 | swada-db | Database を指定 |
| 認証の種類 | 接続文字列 |
| ユーザー名 | db-kanri-sha |
| パスワード |  |

Azureに取り込まれている staticwebapp.database.config.json の接続文字列は、ここで指定した情報で上書きされます。

# 8. 動作確認
下記のcurlコマンドを実行します。何かデータらしきものが出てきたら成功です。
```
$ curl "https://{生成されたホスト名}.azurestaticapps.net/data-api/rest/prod"
```
REST-API でのデータり取り方、更新の仕方等は ドキュメント「[データ API ビルダーの REST](https://learn.microsoft.com/ja-jp/azure/data-api-builder/rest?source=recommendations)」を参照していただく事として、ここで説明を終了したいと思います。

追伸
- GETで返されるデータ件数が多いと nextLink がついてきますが、URLパラメーターに $first=9999999 等と指定して、1リクエストでのレスポンス件数制限を大幅に増やしてれば nextLink を抑制できます。

# 参考: Azure Learning Documents
https://learn.microsoft.com/ja-jp/azure/static-web-apps/configuration#networking

https://learn.microsoft.com/ja-jp/azure/static-web-apps/database-overview

https://learn.microsoft.com/ja-jp/azure/static-web-apps/local-development

https://learn.microsoft.com/ja-jp/azure/data-api-builder/overview-to-data-api-builder?tabs=azure-sql

https://learn.microsoft.com/ja-jp/azure/data-api-builder/rest?source=recommendations