RevenueCatは、iOS、Android、Webなど様々なプラットフォームでアプリ内サブスクリプションを簡素化する強力なサブスクリプション管理サービスです。その主要機能の1つは、購入、更新、キャンセルなどのサブスクリプションイベントについてバックエンドに通知するWebhookを送信する能力です。この記事では、AWS API Gateway、AWS Lambda(Rustで実装)、およびストレージ層としてDynamoDBを使用して、RevenueCat Webhookを処理する方法を探ります。
アーキテクチャ概要
アーキテクチャは以下の主要コンポーネントで構成されています:
- RevenueCat Webhook:RevenueCatはWebhookイベント(サブスクリプションの更新など)をAWS API Gatewayに送信します。
- AWS API Gateway:API Gatewayは、Webhookリクエストのエントリーポイントとして機能し、それらをLambda関数にルーティングします。
- AWS Lambda(Rust):RustでUnixmplemented Implementation of 関を処理し、保存に適した構造に変換します。
- DynamoDB:この NoSQL データベースは、将来の参照と分析のためにサブスクリプション関連データを保存します。
前提条件
- Rustがインストールされ、AWS Lambda環境へのクロスコンパイルの準備ができていること。
- AWS CLIがインストールされ、設定されていること。
- インフラストラクチャ・アズ・コードのデプロイメントのためのTerraform(オプションですが、強く推奨されます)。
ステップバイステップガイド
ステップ1:API Gatewayのセットアップ
API GatewayはRevenueCatがサブスクリプションイベントが発生したときに呼び出すパブリックエンドポイントとして機能します。以下は設定方法です:
-
API Gatewayの作成:
AWSコンソール、CLI、またはTerraformなどのインフラストラクチャ・アズ・コードツールを使用してHTTP APIを作成できます。このガイドでは、API Gatewayをセットアップするためのterraformコードを示します。resource "aws_api_gateway_rest_api" "revenue_cat_webhook" { name = "revenue-cat-webhook" } resource "aws_api_gateway_resource" "webhook_resource" { rest_api_id = aws_api_gateway_rest_api.revenue_cat_webhook.id parent_id = aws_api_gateway_rest_api.revenue_cat_webhook.root_resource_id path_part = "webhook" } resource "aws_api_gateway_method" "webhook_post" { rest_api_id = aws_api_gateway_rest_api.revenue_cat_webhook.id resource_id = aws_api_gateway_resource.webhook_resource.id http_method = "POST" authorization = "NONE" }
-
Lambdaとの統合:
POSTメソッドは、後で設定するLambda関数をトリガーする必要があります。resource "aws_api_gateway_integration" "lambda_integration" { rest_api_id = aws_api_gateway_rest_api.revenue_cat_webhook.id resource_id = aws_api_gateway_resource.webhook_resource.id http_method = aws_api_gateway_method.webhook_post.http_method integration_http_method = "POST" type = "AWS_PROXY" uri = aws_lambda_function.revenue_cat_lambda.invoke_arn }
ステップ2:Rust Lambda関数の実装
Webhookを処理し、関連データを抽出してDynamoDBに保存するRustベースのAWS Lambda関数を構築します。
-
AWS Lambda用のRustセットアップ:
Lambdaの環境へのクロスコンパイルに必要なツールを含むRustがインストールされていることを確認してください:rustup target add x86_64-unknown-linux-musl
-
Lambda関数:
Lambda関数はRevenueCatからの着信JSONを解析し、処理して、DynamoDBに保存します。use lambda_http::{service_fn, Error, IntoResponse, Request}; use serde::{Deserialize, Serialize}; use aws_sdk_dynamodb::{Client, model::PutItemInput}; use std::collections::HashMap; #[derive(Deserialize)] struct WebhookEvent { event: String, product_id: String, app_user_id: String, purchase_date: String, } #[derive(Serialize, Deserialize)] struct SubscriptionData { app_user_id: String, product_id: String, event: String, timestamp: String, } async fn handle_request(event: WebhookEvent, client: &Client) -> Result<impl IntoResponse, Error> { // サブスクリプションデータを保存するためのDynamoDBアイテムを作成 let item = SubscriptionData { app_user_id: event.app_user_id.clone(), product_id: event.product_id.clone(), event: event.event.clone(), timestamp: event.purchase_date.clone(), }; // アイテムをDynamoDBに適した形式に変換 let mut item_map = HashMap::new(); item_map.insert("app_user_id", item.app_user_id.into()); item_map.insert("product_id", item.product_id.into()); item_map.insert("event", item.event.into()); item_map.insert("timestamp", item.timestamp.into()); // アイテムをDynamoDBに書き込む client .put_item(PutItemInput { table_name: "SubscriptionEvents".to_string(), item: item_map, ..Default::default() }) .await?; Ok("Success".into_response()) } #[tokio::main] async fn main() -> Result<(), Error> { let config = aws_config::load_from_env().await; let client = Client::new(&config); lambda_http::run(service_fn(|request: Request| async move { let event: WebhookEvent = serde_json::from_slice(request.body())?; handle_request(event, &client).await })) .await }
-
Lambda関数のデプロイ:
Lambda ランタイム用に関数をコンパイルします:cargo build --release --target x86_64-unknown-linux-musl
バイナリを zip 化し、Lambda にデプロイします:
zip lambda.zip ./target/x86_64-unknown-linux-musl/release/bootstrap aws lambda update-function-code --function-name revenue_cat_lambda --zip-file fileb://lambda.zip
ステップ3:イベント保存用のDynamoDBテーブル
RevenueCatからのサブスクリプションイベントを保存するためのDynamoDBテーブルが必要です。以下は、TerraformでDynamoDBテーブルを定義する方法です:
resource "aws_dynamodb_table" "subscription_events" {
name = "SubscriptionEvents"
hash_key = "app_user_id"
range_key = "timestamp"
billing_mode = "PAY_PER_REQUEST"
attribute {
name = "app_user_id"
type = "S"
}
attribute {
name = "timestamp"
type = "S"
}
}
ステップ4:RevenueCat Webhookの設定
API GatewayとLambda関数をデプロイしたら、RevenueCatがWebhookイベントをAPI Gatewayエンドポイントに送信するように設定する必要があります。
-
RevenueCatダッシュボードで、Webhook設定に移動します。
-
API Gatewayエンドポイントを指す新しいWebhook URLを追加します。URL例:
https://your-api-id.execute-api.region.amazonaws.com/prod/webhook
ステップ5:Webhookのテスト
Postmanやcurlなどのツールを使用して統合をテストできます。例:
curl -X POST https://your-api-id.execute-api.region.amazonaws.com/prod/webhook \
-H "Content-Type: application/json" \
-d '{
"event": "RENEWAL",
"product_id": "com.example.premium",
"app_user_id": "user123",
"purchase_date": "2023-09-13T00:00:00Z"
}'
このエンドポイントに正常にヒットすると、Lambdaはイベントをログに記録し、サブスクリプションデータをDynamoDBテーブルに保存します。
結論
AWS Lambda(Rustで実装)、API Gateway、およびDynamoDBを使用することで、RevenueCat Webhookを処理するためのスケーラブルでコスト効果の高いソリューションを構築できます。このセットアップにより、サブスクリプションイベントをリアルタイムで処理し、さらなる分析やサブスクリプション管理のためにそれらを永続化することができます。このアーキテクチャにより、サーバーレスコンピューティングと強力なサブスクリプション管理プラットフォームの最良の部分を活用しています。