StripeのWebhook処理にAzure Functionsを使ってみる

## はじめに

最近、StripeのWebhookをAzure Functionsで設置する機会がありましたので、その時の手順をまとめたいと思います。

いつもはExpressでAPIサーバーを立てたり、AWS Lambda + API Gateway で処理したりしていたのですが、**Azure Functionsがとても便利**だったのでご紹介をかねて記事にしました。

## 開発環境

必要なものは以下の通りです。CLIはそれぞれ最新バージョンを使用して下さい。

- Node.js  (v14.17.0)
- Stripe CLI
- Azure CLI
- Azure Functions Core Tools（Azure Functionsをローカルで実行するために使います）



## ローカルで関数アプリを作成する

#### 1. プロジェクトをダウンロードする

Node.js用のひな形が私のGitHubに入ってますのでそちらをご活用下さい。
**[プロジェクトをダウンロード](https://github.com/kota-imai/stripe-webhook-azfunc/archive/refs/heads/main.zip)**







#### 2. 必要なパッケージをインストール

`package.json`がある階層に移動して、プロジェクトに必要なパッケージを集めます。

```
 npm install 
```



#### 3. envファイルを作成

ご自身の環境に .env ファイルを作成します。（.env.sampleというファイルが入ってますのでそちらを書き換えて下さい）

- **Stripeのシークレットキー**

  まずはテスト環境のシークレットキーを使用します。ダッシュボードから取得できます。

  [![Image from Gyazo](https://i.gyazo.com/25fe367584c8a6d0261a805dba1ef649.png)](https://i.gyazo.com/25fe367584c8a6d0261a805dba1ef649.png)

- **Webhookシークレット**

Webhookシークレットは**ローカル用の値を取得**します。↓のstripeコマンドを打つとローカル環境で使う用の webhookシークレットが払い出されますのでそちらを使用します。

  ```
 stripe listen
  ```

  [![Image from Gyazo](https://i.gyazo.com/5727d6cc985f896e8e0dd82ceb35a0cd.png)](https://i.gyazo.com/5727d6cc985f896e8e0dd82ceb35a0cd.png)

#### 4. ローカル上で Azure Functions を実行

```
 func start
```

[![Image from Gyazo](https://i.gyazo.com/f5e9b801f79f79650cef86604a3cc354.png)](https://i.gyazo.com/f5e9b801f79f79650cef86604a3cc354.png)
Azure Functions の関数が起動し、localhostで検証が行えるようになります。

#### 5. Stripeイベントをlocalhostで受け取る

次に Stripe CLI を使用してローカルでイベントを傍受します。

新しくターミナルを立ち上げて、以下のコマンドを実行します。`--forward-to` に先ほどのエンドポイントを指定することで、Stripeイベントがフォワーディングされるようになります。

```
 stripe listen --forward-to localhost:7071/api/webhook
```

[![Image from Gyazo](https://i.gyazo.com/a75709163a2d896025d2951ecfa016b5.png)](https://i.gyazo.com/a75709163a2d896025d2951ecfa016b5.png)
参照： [Send real-time Stripe events to your server | Stripe のドキュメント](https://stripe.com/docs/stripe-cli/webhooks#forward-events)



#### 6. Stripe のイベントを発火する

ローカルアプリでWebhookを受け取れるかテストをしてみましょう。Stripe イベントは CLI から簡単に発火させることができます。

さらに別のターミナルを起動して、コマンドを実行します。

```
stripe trigger customer.created
```

[![Image from Gyazo](https://i.gyazo.com/4eb73d98acadd00bedc4806bada0c984.png)](https://i.gyazo.com/4eb73d98acadd00bedc4806bada0c984.png)
参照： [Trigger Stripe events to test a webhooks integration | Stripe のドキュメント](https://stripe.com/docs/stripe-cli/trigger#step-2:-trigger-events)



#### 7. Azure Functions のログを確認

Azure Functions を起動しているターミナルでログを確認してみると、、

[![Image from Gyazo](https://i.gyazo.com/9da9250f4455270063614f1dbe961530.png)](https://i.gyazo.com/9da9250f4455270063614f1dbe961530.png)

Stripeイベント `customer.created` の受信に成功していることが分かります。

問題なく動いていることが確認できたので、ローカルでの検証はここまでとします。これまでに起動したターミナルはすべて終了して構いません。

次はこの関数アプリを Azure 上にデプロイしていきます。





## Azure上にリソースを作成

#### 1. 関数アプリを新しく作成

Azureの管理コンソールを開いて、新しく関数アプリを作成します。先ほど作成した関数アプリを乗せる器を用意するイメージです。

[![Image from Gyazo](https://i.gyazo.com/86c1916921f7f5c7ddc169454eb9bef7.jpg)](https://i.gyazo.com/86c1916921f7f5c7ddc169454eb9bef7.jpg)

左端のペインから「関数アプリ」を選択して、新しくリソースを作成します。



#### 2.「基本」
使用するサブスクリプションとリソースグループ、関数アプリ名、ランタイムスタック、バージョン、地域をそれぞれ入力します。

[![Image from Gyazo](https://i.gyazo.com/68c861d23211e546718356e47e85e963.png)](https://i.gyazo.com/68c861d23211e546718356e47e85e963.png)

今回のアプリはStripeからのWebhookのみを受け取るので、StripeのWebhook送信サーバーを起点にリージョンを選びます。



 [Webhookを送信するIPアドレス一覧](https://stripe.com/docs/ips#webhook-%E9%80%9A%E7%9F%A5) から、それぞれのサーバーの位置情報を調べてみました。「アメリカ中心、一部インド」という地理構成のようです。
したがって、今回は**Central US** を選択するのが良さそうです。

| IP address     | Country                  | States      | City     |
| -------------- | ------------------------ | ----------- | -------- |
| 3.18.12.63     | United States of America | Ohio        | Columbus |
| 3.130.192.231  | United States of America | Ohio        | Columbus |
| 13.235.14.237  | India                    | Maharashtra | Mumbai   |
| 13.235.122.149 | India                    | Maharashtra | Mumbai   |
| 18.211.135.69  | United States of America | Virginia    | Ashburn  |
| 35.154.171.200 | India                    | Maharashtra | Mumbai   |
| 52.15.183.38   | United States of America | Ohio        | Columbus |
| 54.88.130.119  | United States of America | Virginia    | Ashburn  |
| 54.88.130.237  | United States of America | Virginia    | Ashburn  |
| 54.187.174.169 | United States of America | Oregon      | Portland |
| 54.187.205.235 | United States of America | Oregon      | Portland |
| 54.187.216.72  | United States of America | Oregon      | Portland |

参照： [ドメインと IP アドレス | Stripe のドキュメント](https://stripe.com/docs/ips)



#### 3.「ホスティング」
[![Image from Gyazo](https://i.gyazo.com/82af4b0381878a9ee568c4ac90e6ee1b.png)](https://i.gyazo.com/82af4b0381878a9ee568c4ac90e6ee1b.png)
オペレーティングシステムはWindowsでもLinuxでもどちらでもokです。

#### 4.「ネットワーク」
[![Image from Gyazo](https://i.gyazo.com/356c67349f16f41e58ed9cdb07ac0bc9.png)](https://i.gyazo.com/356c67349f16f41e58ed9cdb07ac0bc9.png)

#### 5.「監視」
[![Image from Gyazo](https://i.gyazo.com/c1b7310c6a11b875624fbe04c922719f.png)](https://gyazo.com/c1b7310c6a11b875624fbe04c922719f.png)
必要に応じて有効・無効を切り替えて下さい。

#### 6.「タグ」
[![Image from Gyazo](https://i.gyazo.com/a7227182aaf1af77905c77314a675dcc.png)](https://gyazo.com/a7227182aaf1af77905c77314a675dcc.png)
必要に応じてタグを設定して下さい。

#### 7.「確認および作成」
![img](https://gyazo.com/642bd172680b73759e1d3aa2b85f307d.png)
内容を確認して、「作成」します。

#### 8. CLIを使った関数アプリの作成
```
az functionapp create --name <関数アプリ名>
    --resource-group <リソースグループ名>
    --storage-account <ストレージアカウント名>
    --consumption-plan-location centralus
    --functions-version 3
    --disable-app-insights true
    --os-type Windows
    --runtime node
    --runtime-version 14
```

参照： [az functionapp | Microsoft Docs](https://docs.microsoft.com/ja-jp/cli/azure/functionapp?view=azure-cli-latest#az_functionapp_create)



## Webhookエンドポイントを登録

#### 1. Azure 上のエンドポイントURLを取得
後続で必要になるので、先にStripeにWebhook エンドポイントを追加します。

```
https://<関数アプリ名>.azurewebsites.net/api/webhook
```
 がエンドポイントURLとなります。 

[![Image from Gyazo](https://i.gyazo.com/32fabba012a68d2d3b499db51bb0df56.png)](https://gyazo.com/32fabba012a68d2d3b499db51bb0df56.png)

#### 2. StripeにWebhookエンドポイントを追加
[StripeのWebhook一覧画面](https://dashboard.stripe.com/test/webhooks)からエンドポイントを追加します。エンドポイントURLとリッスンするイベントを選択して「イベントを追加」します。
[![Image from Gyazo](https://i.gyazo.com/ba483433bcfc2df966a5e256f4ddb842.png)](https://gyazo.com/ba483433bcfc2df966a5e256f4ddb842.png)
[![Image from Gyazo](https://i.gyazo.com/16144afe9e9063c55ad156b8f7e25f28.png)](https://gyazo.com/16144afe9e9063c55ad156b8f7e25f28.png)

#### 3. Webhook シークレットキーを取得
署名シークレットをメモしておきます。あとで使います。
[![Image from Gyazo](https://i.gyazo.com/48bb6ab2d79d63a1fc29360b6c0c3aef.png)](https://gyazo.com/48bb6ab2d79d63a1fc29360b6c0c3aef.png)

#### 4. Stripe CLIを使ったエンドポイント追加
```
stripe webhook_endpoints create --url "https://<関数アプリ名>.azurewebsites.net/api/webhook" --data "enabled_events[]=customer.created"
```
参照： [Stripe API Reference - Create a webhook endpoint](https://stripe.com/docs/api/webhook_endpoints/create?lang=cli)

## 関数アプリに環境変数を設定
#### 1. .envファイルを削除
.envファイルはローカル環境用なので、こちらは**削除**して下さい。
また、`webhook/index.js` の１行目をコメントアウトします。

```javascript:index.js
// require('dotenv').config(); // Remove it when runs on prod
```

#### 2. アプリケーション設定を追加
先ほど作成した関数アプリのコンソール画面から、アプリケーション設定（環境変数）を追加します。
[![Image from Gyazo](https://i.gyazo.com/905b6e5be6f44383f3197caa80b9aa13.png)](https://gyazo.com/905b6e5be6f44383f3197caa80b9aa13.png)

設定に「STRIPE_SECRET_KEY」と「STRIPE_WEBHOOK_SECRET」を追加します。追加後に「保存」を押すのをお忘れなく。

| Key                   | Value                                     |
| --------------------- | ----------------------------------------- |
| STRIPE_SECRET_KEY     | < テスト環境のAPIキー>                   |
| STRIPE_WEBHOOK_SECRET | < Webhookの署名シークレット> |


#### 3. CLIを使ったアプリケーション設定の追加

```
az functionapp config appsettings set --name <関数アプリ名> --resource-group <リソースグループ名> --settings STRIPE_SECRET_KEY=<APIキー>
az functionapp config appsettings set --name <関数アプリ名> --resource-group <リソースグループ名> --settings STRIPE_WEBHOOK_SECRET=<Webhookの署名シークレット>
```

参照： [Azure Functions で Function App の設定を構成する | Microsoft Docs](https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-how-to-use-azure-function-app-settings?tabs=azure-cli)

## デプロイ
#### 1. プロジェクトをzipファイル化
デプロイ方法は色々ありますが、今回はzipにして Azure CLI でデプロイしていきます。
まず、プロジェクト全体を圧縮して「app.zip」というファイル名で保存します。
[![Image from Gyazo](https://i.gyazo.com/7d7c9a80ebf05a2f01431179375c2575.png)](https://gyazo.com/7d7c9a80ebf05a2f01431179375c2575.png)

#### 2. デプロイする
次に Azure CLI を使ってデプロイします。少し時間がかかります。

```
az functionapp deployment source config-zip --name <関数アプリ名> --resource-group <リソースグループ名> --src app.zip
```

参照： [az functionapp deployment source | Microsoft Docs](https://docs.microsoft.com/ja-jp/cli/azure/functionapp/deployment/source?view=azure-cli-latest#az_functionapp_deployment_source_config_zip)
#### 3. イベントを発火してテストしてみる
デプロイが完了したら [Stripeのダッシュボード](https://dashboard.stripe.com/test/webhooks/) からテストイベントを送ってみます。Azure上のWebhookエンドポイントに `customer.created` イベントを送信します。

エンドポイントから 「Customer created!」とレスポンスが返ってくれば成功です。
[![Image from Gyazo](https://i.gyazo.com/f186957b038da975ebac24aef7dba2e8.png)](https://gyazo.com/f186957b038da975ebac24aef7dba2e8.png)
[![Image from Gyazo](https://i.gyazo.com/475cbf94bc5d4e59525256168a2f8172.png)](https://gyazo.com/475cbf94bc5d4e59525256168a2f8172.png)

#### 4. そのほかのデプロイ方法
エディタにVSCodeを使っている方は、拡張機能を使うと簡単にデプロイできます。おすすめです。

参照： 
・ [Azure Functions のデプロイ テクノロジ | Microsoft Docs](https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-deployment-technologies)
・ [Visual Studio Code を使用して JavaScript 関数を作成する - Azure Functions | Microsoft Docs](https://docs.microsoft.com/ja-jp/azure/azure-functions/create-first-function-vs-code-node#deploy-the-project-to-azure)

## Power Automateで各イベントを処理する
イベントの処理をコードで実装することもできますが、Azure Service Bus などのメッセージングサービスを使うと、Power Automate や Logic Apps のような**ノーコードのサービスに連携することも可能**です。

CheckoutやPayment Linksなど支払いのインターフェース部分はノーコードのソリューションがありますが、裏側の処理はある程度コーディングが必要になります。そこでPower AutomateやLogic Appsを活用して、更にコード量を減らせないか試してみました。

決済後は「顧客にメール送信する」、「受注データを登録する」といったアクションが考えられますが、これらはPower Automateで簡単に実装することができます。
[![Image from Gyazo](https://i.gyazo.com/6252f773c85fd1b47d9dbe91c68e93ff.png)](https://gyazo.com/6252f773c85fd1b47d9dbe91c68e93ff.png)
**⇩⇩⇩**
[![Image from Gyazo](https://i.gyazo.com/7e1359d0f2caf84fe28cd2f75dbf1070.jpg)](https://gyazo.com/7e1359d0f2caf84fe28cd2f75dbf1070.png)


#### 1. Service Bus キューを作成
Service BusはAzure上のクラウドメッセージングサービスです。サービスの概要やリソースの作成方法はドキュメントをご参照下さい。
[Azure portal を使用して Service Bus キューを作成する - Azure Service Bus | Microsoft Docs](https://docs.microsoft.com/ja-jp/azure/service-bus-messaging/service-bus-quickstart-portal)

#### 2. キューの重複メッセージ検出を有効にする
Stripeのドキュメントによると、Webhook エンドポイントから同じイベントが複数回送られてくる可能性があるようです。
したがって、それらを処理するアクションが二重で行われないよう(or 二重で行われてもデータ整合性がとれるよう)アプリケーション側で対策が必要になります。
参照： [Webhook 使用のベストプラクティス | Stripe のドキュメント](https://stripe.com/docs/webhooks/best-practices#duplicate-events)

Service Busにはメッセージ重複を排除するオプションがありますので、キューを作成する際はそちらを有効にします。これにより、Service Bus以降の<b>イベント処理を冪等（べきとう）に</b>します。
[![Image from Gyazo](https://i.gyazo.com/58310099bce2e78378780b95cf342bc6.jpg)](https://gyazo.com/58310099bce2e78378780b95cf342bc6)

:::note warn
Service Bus の Standard と Premium レベルで重複検出オプションを設定可能です。Basic レベルでは、重複検出はサポートされませんのでご注意ください。
<a href="https://azure.microsoft.com/ja-jp/pricing/details/service-bus">料金 - Service Bus | Microsoft Azure</a>
:::

#### 3. 接続文字列を環境変数に追加
アプリケーション設定に「SB_CONNECTION_STRING」を追加します。

| Key                   | Value                                     |
| --------------------- | ----------------------------------------- |
| SB_CONNECTION_STRING | < 名前空間への接続文字列 >                   |

```
az functionapp config appsettings set --name <関数アプリ名> --resource-group <リソースグループ名> --settings SB_CONNECTION_STRING=<接続文字列>
```

#### 4. function.jsonを変更
`function.json`をいじって、この関数がService Busへアウトプットがあることを明記します。queueNameの項目には作成したキューの名前を入れます。

```diff_javascript:webhook/function.json
{
  "bindings": [
    {
      "authLevel": "anonymous",
      "type": "httpTrigger",
      "direction": "in",
      "name": "req",
      "methods": [
        "post"
      ]
    },
    {
      "type": "http",
      "direction": "out",
      "name": "res"
    },
+   {
+     "type": "serviceBus",
+     "queueName": "<キューの名前>",
+     "connection": "SB_CONNECTION_STRING",
+     "direction": "out",
+     "name": "queue"
+   }
  ]
}
```

#### 5. index.jsを編集する
`customer.created` イベントを受け取ったときにService Busへメッセージ送信するようにしてみます。編集したら再度デプロイします。

```diff_javascript:webhook/index.js(一部抜粋)
// Handle each events from here
if (eventType === 'customer.created') {
+    context.bindings.queue = {
+       body: data,
+       label: eventType,
+   };
    context.res = {
        status: 200,
        body: 'customer created!'
    };
}
```
参照： [Azure Functions における Azure Service Bus の出力バインド | Microsoft Docs](https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-bindings-service-bus-output?tabs=javascript)

#### 6. Power Automateにフローを作成
メッセージを処理するフローをPower Automateに作成します。Teamsに内容を通知する簡単なフローです。
[![Image from Gyazo](https://i.gyazo.com/98d5948ed49f9862472aa270a781c1a2.png)](https://gyazo.com/98d5948ed49f9862472aa270a781c1a2.png)

#### 7. Stripeに顧客を追加
コンソールから新しい顧客を追加して、フローが起動するか確認します。
[![Image from Gyazo](https://i.gyazo.com/d324c8822aa8a4ff3422d17e71d7c3d1.png)](https://gyazo.com/d324c8822aa8a4ff3422d17e71d7c3d1.png)

#### 8. 実行結果
無事、Teamsにメッセージが届きました！フローを編集すればOutlookやDataverseなど他のサービスにも連携できそうです！
[![Image from Gyazo](https://i.gyazo.com/87874a9cfcf3ebc38ba354f0bce9adc5.png)](https://gyazo.com/87874a9cfcf3ebc38ba354f0bce9adc5.png)

## IPアドレスを制限してアプリケーションを保護する

#### 1. アクセス制限を設定
最後に、より安全に利用するためにStripeのWebhookサーバー以外からのリクエストを拒否する設定をしていきます。

前述のように [Webhookを送信するIPアドレスの一覧](https://stripe.com/docs/ips#webhook-%E9%80%9A%E7%9F%A5) は公開されていますので、**これらのIPアドレスのみアクセスを許可して他はすべて拒否する**よう設定します。
以下のコマンドを流してアクセス制限の設定を行います。コンソール画面からもできますが **CLIのほうが楽**です。

```
az functionapp config access-restriction add --resource-group <リソースグループ名> --name <関数アプリ名> --rule-name ipAddress1 --ip-address 3.18.12.63/32 --priority 100 --action Allow
az functionapp config access-restriction add --resource-group <リソースグループ名> --name <関数アプリ名> --rule-name ipAddress2 --ip-address 3.130.192.231/32 --priority 101 --action Allow
az functionapp config access-restriction add --resource-group <リソースグループ名> --name <関数アプリ名> --rule-name ipAddress3 --ip-address 13.235.14.237/32 --priority 102 --action Allow
az functionapp config access-restriction add --resource-group <リソースグループ名> --name <関数アプリ名> --rule-name ipAddress4 --ip-address 13.235.122.149/32 --priority 103 --action Allow
az functionapp config access-restriction add --resource-group <リソースグループ名> --name <関数アプリ名> --rule-name ipAddress5 --ip-address 18.211.135.69/32 --priority 104 --action Allow
az functionapp config access-restriction add --resource-group <リソースグループ名> --name <関数アプリ名> --rule-name ipAddress6 --ip-address 35.154.171.200/32 --priority 105 --action Allow
az functionapp config access-restriction add --resource-group <リソースグループ名> --name <関数アプリ名> --rule-name ipAddress7 --ip-address 52.15.183.38/32 --priority 106 --action Allow
az functionapp config access-restriction add --resource-group <リソースグループ名> --name <関数アプリ名> --rule-name ipAddress8 --ip-address 54.88.130.119/32 --priority 107 --action Allow
az functionapp config access-restriction add --resource-group <リソースグループ名> --name <関数アプリ名> --rule-name ipAddress9 --ip-address 54.88.130.237/32 --priority 108 --action Allow
az functionapp config access-restriction add --resource-group <リソースグループ名> --name <関数アプリ名> --rule-name ipAddress10 --ip-address 54.187.174.169/32 --priority 109 --action Allow
az functionapp config access-restriction add --resource-group <リソースグループ名> --name <関数アプリ名> --rule-name ipAddress11 --ip-address 54.187.205.235/32 --priority 110 --action Allow
az functionapp config access-restriction add --resource-group <リソースグループ名> --name <関数アプリ名> --rule-name ipAddress12 --ip-address 54.187.216.72/32 --priority 111 --action Allow
```

コマンド実行後に再度コンソール画面を確認するとアクセス制限が適用されているはずです。
[![Image from Gyazo](https://i.gyazo.com/bf53523758c03a4d08070aab7291dd4b.png)](https://gyazo.com/bf53523758c03a4d08070aab7291dd4b.png)
[![Image from Gyazo](https://i.gyazo.com/34986bf08c38f874fa17e4a0cda3fcae.png)](https://gyazo.com/34986bf08c38f874fa17e4a0cda3fcae.png)

#### 2. アクセスしてみる
試しにブラウザからアクセスしようとするとしっかりと拒否されました。設定が効いているようです。
[![Image from Gyazo](https://i.gyazo.com/7a9735f4ea8b164b73ab2da00d85ab9c.png)](https://gyazo.com/7a9735f4ea8b164b73ab2da00d85ab9c.png)

:::note warn
アクセス制限を設定すると、<b>自分のPCからデプロイもできなくなる</b> のですべての機能を実装した後に行ってください。
:::

:::note warn
StripeのWebhookサーバーが追加された場合はアクセス制限を変更する必要があります。最新情報を追うために公式のメーリングリストの購読をおすすめします。
<a href="https://groups.google.com/a/lists.stripe.com/g/api-announce/">Stripe API Announcements - Googleグループ</a>
:::

## コールドスタートに注意！
Azure Functions の従量課金プランを使用する場合、最後のリクエストから20分を経過するとインスタンス数が 0 にスケールダウンしてしまうため次回要求への応答が数秒遅れる場合があります。このとき、Stripe側ではレスポンスエラーと判断され、数分後に再度Webhookリクエストが送られてきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/594998/60bcd0c7-81f6-c0c5-d0ce-d16e7c60c447.png)

Service Busで重複メッセージは排除していますが、レスポンスエラーが気になる方は以下の対策が可能です。

- <b>課金する</b>
常時稼働の [App Service プラン](https://docs.microsoft.com/ja-jp/azure/azure-functions/dedicated-plan)か、[Premium プラン](https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-premium-plan)にアップグレードすることで解決できます。しかし、「使った分だけ」のサーバーレスの利点はつぶれてしまいます。

- <b>一定時間毎にリクエストを送ってコールドスタートを回避する</b>
私は15分ごとに関数アプリのURLにGETリクエストを送ってインスタンス数が 0 にならないように維持しています。

参照：[Understanding serverless cold start  | Microsoft Azure](https://azure.microsoft.com/ja-jp/blog/understanding-serverless-cold-start/)



## ソースコードについて
https://github.com/kota-imai/stripe-webhook-azfunc
ご自由に使って頂いて構いません。もし間違いなどがありましたらそっと教えて頂けると幸いです。

## まとめ
とても長くなってしまいました。。最後まで読んで下さった方はいるのでしょうか笑

当たり前のことですが、決済サービスが絡む =**人様のお金を扱う**ということですのでセキュリティには十二分に気を付けたいところですね。そんな中でStripeとAzure Functionsはその思いを強力にサポートしてくれます。

最後まで読んでいただき、ありがとうございました。この記事を読まれた方の開発の足掛かりになれば幸いです。