【Stripe】Webhookの実装をAzure環境に構築する【後編】

◆ Live配信スケジュール ◆
サイオステクノロジーでは、Microsoft MVPの武井による「わかりみの深いシリーズ」など、定期的なLive配信を行っています。
⇒ 詳細スケジュールはこちらから
⇒ 見逃してしまった方はYoutubeチャンネルをご覧ください
【5/21開催】Azure OpenAI ServiceによるRAG実装ガイドを公開しました
生成AIを活用したユースケースで最も一番熱いと言われているRAGの実装ガイドを公開しました。そのガイドの紹介をおこなうイベントです!!
https://tech-lab.connpass.com/event/315703/

こんにちは、サイオステクノロジーの佐藤 陽です。
今日は、Stripe の Webhook のハンドリングを Azure 環境で実際に組み立ててみたいと思います。

  • Azure上でStripe の Webhook を活用したアプリを構築したい
  • Webhook のハンドリングのベストプラクティスを知りたい
  • さくっと動作確認できる環境を作りたい

という方は是非最後までご覧ください!

なおこの記事は後編になります。
前編はこちら ↓

【Stripe】Webhookの実装をAzure環境に構築する【前編】

はじめに

Webhook とは、Stripe 上で何かしらのイベントが発生した場合にイベントが飛ばされる仕組みです。

例えば「Stripe 上に Customer が作成された時」や、「サブスクリプションが作成された時」などのタイミングで、Stripe から指定したエンドポイントに対してイベントが発行されます。

これに基づいてアプリケーション側で処理を行う事で、イベントドリブンな機能の実装が行えます。

要件

今回お試しで作ってみるアプリは以下のようなものとします。
  • Stripe 上に Customer を作成できる API を実装する
    • 受け付けるパラメータとしては、「名前」,「メールアドレス」とする
    • 顧客作成時にサブスクリプションの契約は不要とする
  • 顧客作成が完了したタイミングで、BlobStorage に顧客情報を保存する
    • 保存する情報は「CustomerId」,「名前」,「メールアドレス」,「作成日時」とする
    • {CustomerId}.json」をファイル名とする json 形式で保存する

# Azure 構成図

これを満たす Azure のシステムを組み立てていきます。

 

処理の流れとしては以下のような流れです。

  1. クライアントが WebApps にて実装した API に対して Customer 作成の要求を出します。
  2. API が Stripe の CreateCustomerAPI を実行し、Stripe 上に Customer を作成します。
  3. Stripe 上で Customer が作成されたタイミングで、customer.created の Webhook イベントがされます。
  4. イベントを受けた WebApps は ServiceBus の Queue に対して Enqueue します。
  5. Enqueue からのメッセージをトリガーとして、Functions が実行されます。
  6. Functions が StorageAccount に対してファイルを保存します。

なお今回の記事では 5.~6.を扱います。 1.~4.に関しては前編で紹介済みです。

リソース準備

Azure Functions

アプリケーション作成

ServiceBusからのメッセージをトリガーとして処理が行われるAzure Functionsのプロジェクトを作成していきます。

func init StripeWebhookFunction

Use the up/down arrow keys to select a worker runtime:dotnet
Use the up/down arrow keys to select a language:c#

cd StripeWebhookFunction

func new --name ServiceBusTriggerFunction
Use the up/down arrow keys to select a template:Function name: ServiceBusTriggerFunction

Azure Functions作成

次にAzure Functionsのリソースを作成していきます。

今回は以下の内容で作成します。

  • .NET 6
  • OS:Windows
  • サーバーレスプラン

ApplicationSettingsの設定

ServiceBusTriggerを利用する場合、Azure Functionsの設定で1点注意する点があります。

こちらのドキュメントにもかかれているのですが、接続するServiceBusのNameSpaceをApplication Settingsに設定する必要があります。

Portal画面から以下の値を追加しましょう。

{
    "ServiceBusConnection__fullyQualifiedNamespace" : "sbns-stripe-webhook.servicebus.windows.net"
}

Azure Blob Storage

次にBlob Storageを作っていきます。

ただこちらは特筆するべき点は特にないので、要件に合わせて作成してください。

手元の環境ではコストを抑えるために、Standard, LRSで作成してあります。

作成後、アップロード用のBlobコンテナを作成しておきます。
今回はcustomerというBlobコンテナを作成しました。

RBAC の設定

今回もリソース間のRBACの設定を行っていきます。

今回のシステムを実装するためには

  • Azure Functionsがキューのメッセージを受信できること
  • Azure FunctionsがStorageAccountに対して書き込みができること

が必要です。

前編のWebApps同様、Azure Functionsの SystemAssignedManagedIdentity の設定を行い、RBAC を設定します。

まずは Azure Functions のポータル画面へと遷移し、ID ブレードから設定してきます。
「状態」をオンにして「保存」を押すと、一意の ID が割り振られます。

では次に ServiceBus の画面へ行き、権限を割り当てます。
先ほどのドキュメントに合った通り、「Azure Service Bus のデータ受信者」の Role を追加します。

StorageAccountに対しても同様に設定を行っていきます。
Blobに対する書き込みが必要なので「ストレージ BLOB データ共同作成者」を追加します。

これで準備 OK なので、実装に移りましょう。

実装

それではキューへのメッセージ追加をトリガーとするアプリケーションを作成していきます。

先ほどサンプルアプリを作成したので、それをベースに改良していきます。

まず、こちらもStripeのパッケージをインストールしておきましょう。

dotnet add package Stripe.net --version 42.4.0

また、ServiceBusのドキュメントにもあるように

ManagedIdentityを使って接続を行うためにServiceBusのSDKをインストール&アップデートしておきます。

dotnet add package Microsoft.Azure.WebJobs.Extensions.ServiceBus --version 5.2.0

実装していく処理の内容としては

  1. メッセージを読み取り、StripeのEventの形にパース
  2. イベントごとに処理分岐
  3. 内容を読み取り、BlobStorageに保存

という流れです。

using System;
using System.Threading.Tasks;
using Azure.Identity;
using Azure.Storage.Blobs;
using Microsoft.Azure.WebJobs;
using Microsoft.Extensions.Logging;
using Stripe;

namespace StripeWebhookFunction
{
    public class ServiceBusTriggerFunction
    {
        [FunctionName("ServiceBusTriggerFunction")]
        public async Task Run([ServiceBusTrigger("sbq-stripewebhook", Connection = "ServiceBusConnection")] string message, ILogger log)
        {
            Event stripeEvent = EventUtility.ParseEvent(message);
            switch (stripeEvent.Type)
            {
                case "customer.created":
                    Customer customer = stripeEvent.Data.Object as Customer;
                    BlobContainerClient blobContainerClient = new(new Uri("https://ststripewebhook.blob.core.windows.net/customer"), new DefaultAzureCredential());
                    BlobClient blobClient = blobContainerClient.GetBlobClient($"{customer.Id}.json");
                    CustomerDataModel model = new(customer.Created, customer.Id, customer.Name, customer.Email);
                    await blobClient.UploadAsync(BinaryData.FromString(Newtonsoft.Json.JsonConvert.SerializeObject(model)), true);
                    break;
                default:
                    break;
            }
        }

        public class CustomerDataModel
        {
            public  DateTime Created { get; set; }
            public  string Id { get; set;}
            public  string Name { get; set; }
            public  string EMailAddress { get; set; }
            public CustomerDataModel(DateTime created, string id, string name, string eMailAddress)
            {
                Created = created;
                Id = id;
                Name = name;
                EMailAddress = eMailAddress;
            }
        }
    }
}

Eventオブジェクトを生成した後に、各Objectでキャストすれば、いつものStripeオブジェクトが生成できますね。
一度オブジェクトIdが分かってしまえば、そこから再度Stripeに問い合わせたりと、後はやりたい放題です。

注意点としては、
ParseEventを行う際に、Webhookのイベントのバージョンと、StripeのSDKのバージョンの不一致があるとエラーが発生してしまいます。
(自分もさっき無意識でエンドポイントの設定していたら、このエラーに直面してました。:((

その際、以下のようにエラーメッセージにそれぞれのAPIバージョンの記載があると思うので、エラーメッセージを見て対応してください。

ServiceBusTriggerFunction Received event with API version 2022-08-01, but Stripe.net 42.4.0 expects API version 2023-08-16. We recommend that you create a WebhookEndpoint with this API version.

動作確認

ではこのアプリケーションをAzure Functionsにデプロイし、動作確認しましょう。

デプロイ完了後に、前回作成したWebAppsのCreateCustomerAPIを実行します。

POST https://app-stripewebhook.azurewebsites.net/api/customers

すると、BlobStorageにファイルが作成されていることが確認できました。

これで以下のステップを全て網羅することができ
今回の要件を満たすアプリケーションを作成することができました。

  1. クライアントが WebApps にて実装した API に対して Customer 作成の要求を出します。
  2. API が Stripe の CreateCustomerAPI を実行し、Stripe 上に Customer を作成します。
  3. Stripe 上で Customer が作成されたタイミングで、customer.created の Webhook イベントがされます。
  4. イベントを受けた WebApps は ServiceBus の Queue に対して Enqueue します。
  5. Enqueue からのメッセージをトリガーとして、Functions が実行されます。
  6. Functions が StorageAccount に対してファイルを保存します。

まとめ

今回は前後編に分けて、StripeのWebhookのハンドリングをAzure上で構築してみました。

Stripeとしての主なポイントとしては

  • Webhook受信時のセキュリティ面を意識すること(署名, IPアドレス等)
  • Webhookのイベントを受けたら即座に2xxを返して、その後の処理は他のアプリに任せること
  • Webhookのイベントのバージョンと、APIのバージョンの整合性をとること

の3点くらいかなと思います。

あとはAzureのアーキテクチャの部分として

  • Managed Identityを使ったリソース間連携
  • ServiceBusTriggerのAzureFunctionsの実装

など注意して実装してみてください。

今回のものをベースとしてもらえれば、他のStripeイベントも問題なく扱えるかと思いますし
イベント発行を起点としてメールを送信したり、メッセージアプリに通知を飛ばしたりなど様々なことが出来ると思います。
Webhook、非常に便利なので使いこなしていきたいですね。

長々と呼んでいただきありがとうございました!
ではまた!

アバター画像
About 佐藤 陽 52 Articles
ロードバイクやトレランなど、走ることが好きなサーバーサイドエンジニア。組み込み系からWeb系へとジョブチェンジし、現在はAzureを使ったWebアプリの開発や、DevOpsの構築を行っています。
ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

役に立った 役に立たなかった

0人がこの投稿は役に立ったと言っています。


ご覧いただきありがとうございます。
ブログの最新情報はSNSでも発信しております。
ぜひTwitterのフォロー&Facebookページにいいねをお願い致します!



>> 雑誌等の執筆依頼を受付しております。
   ご希望の方はお気軽にお問い合わせください!

Be the first to comment

Leave a Reply

Your email address will not be published.


*


質問はこちら 閉じる