はじめに
Stripeは、オンライン決済を提供するプラットフォームです。
サブスクリプション課金やクレジットカード決済を自前で実装する代わりに、Stripeが提供するAPIを呼び出すことで、決済まわりの複雑な処理を任せられます。
保守しているRailsアプリケーションでは、このStripeとの連携に公式Ruby gem stripeを使っています。
今回、このstripe gemのメジャーバージョンアップに初めて対応しました。
対応する中で、gemのバージョニング方式の変化やAPIバージョンの扱いなど、事前に知らないとつまずきやすいポイントがいくつかあったため、そのときの記録として残しておきます。
Stripe gem のバージョニング方式
stripe gemは、v9.0.0を境にAPIバージョンとの関係が変わっています。
v8以前は、gem側でStripe.api_versionを指定しない限りStripe-Versionヘッダーを送らず、リクエストはStripe管理者コンソール(ダッシュボード)側で設定したアカウントのデフォルトAPIバージョンに追従していました。
つまり、v8以前はgemをアップデートしても、使われるAPIバージョンはダッシュボード側の設定次第でした。
v9.0.0以降は、gem自体が特定のAPIバージョンに固定(ピン留め)されるようになり、常にそのバージョンをStripe-Versionヘッダーで送るようになりました。これにより、ダッシュボードのデフォルトAPIバージョンをgem側から使うことはできなくなり、代わりにgemのバージョンそのものがAPIバージョンを決めるようになっています。
そのため、v9.0.0以降でgemをメジャーアップデートすることは、そのままStripe APIのバージョンを引き上げることを意味します。
Stripe API バージョンの変更について
Stripe公式は、gem に同梱された API バージョンにそのまま追従する運用を推奨しています。明示的に Stripe.api_version を上書きしなければ、多くのアプリケーションはこの推奨通りの設定で使っているはずです。
確認しないといけないこととしては、API バージョンが変わると、Stripe から返ってくるレスポンスの形状も変わりうることです。フィールドが別の場所に移動していたり、あるフィールド自体が廃止されていたりすると、それを前提に書かれていたコードが正しく動かなくなります。
厄介なのは、こうした変更の一部は例外を起こさずに、値が黙って空になるだけで済んでしまう場合があることです。
例外が起きないぶん、テストが「値が期待通り入っていること」まで検証していない限り、気づかないまま動き続けてしまいます。
今回対応したアプリケーションのテストでは決済処理のモックに stripe-mock を使っていました。
この stripe-mock のバージョンを最新に追従させたところ、それまで見えていなかったレスポンス形状の差分がテスト上で顕在化し、破壊的変更の影響を洗い出すことができました。
stripe-mock を使ってテストを作成している場合は、gem 自体の CHANGELOG だけでなく、stripe-mock のバージョンが古くなっていないかも合わせて確認するとよさそうです。
Stripe Webhook API バージョンについて
ここまでの API バージョンは、アプリケーションから Stripe へリクエストを送る際に使われるものです。
これとは別に、Stripe からアプリケーションへ Webhook でイベントを通知する際にも、API バージョンが存在します。
この Webhook 側の API バージョンは、リクエスト側のようにコードや gem の設定だけでは変わりません。
Stripe の管理者コンソール上で、アカウントのデフォルト API バージョンを明示的に引き上げる操作が必要になります。
また、Webhook エンドポイントを作成した時点のバージョンが個別に固定されている場合、アカウントのデフォルトバージョンを上げても、そのエンドポイントには反映されない点にも注意が必要です。
段階的に進めるなら、まずリクエスト側のgemアップデートを先に済ませ、Webhook側のバージョンは別途、管理者コンソールで確認しながら引き上げる、という順序が現実的だと思います。
動作確認について
Stripeは、本番環境とは別にサンドボックス環境を提供しています。
サンドボックス環境では、テスト用のカード番号を使って、実際の決済フローと同じ流れ(サブスクリプション作成、プラン変更、3Dセキュア認証など)を試すことができます。
gemやAPIバージョンをアップデートした際は、単体テストやCIが通ることに加えて、このサンドボックス環境で一連の決済フローを実際に動かして確認しておきたいところです。
特にWebhookが絡む処理は、リクエスト・レスポンスのやり取りだけでは再現しきれない部分があるため、サンドボックス環境でWebhookを実際に受信させた上での確認が有効だと考えます。
開発環境でWebhookを受信するには、Stripe CLIを使います。
stripe loginで CLI を Stripe アカウントに接続し、stripe listen --forward-to localhost:3000/webhooks/stripe のようなコマンドを実行すると、サンドボックス環境で発生したイベントがローカルのエンドポイントに転送されるようになります(ポートやパスは実際のアプリケーションのWebhookエンドポイントに合わせます)。
このコマンドの実行結果には、そのセッション用の Webhook 署名シークレットが表示されるので、STRIPE_WEBHOOK_SECRETのような環境変数にセットしておくと、署名検証まで含めて動作を確認できます。
stripe listen を起動したまま、管理画面や API 経由で実際に決済操作を行えば、対応するイベントがそのままローカルに転送されてきます。
任意のイベントだけを単発で試したい場合は、stripe trigger payment_intent.succeededのようにstripe triggerコマンドで疑似的なイベントを発生させることもできます。
おわりに
stripe gemのメジャーアップデートは、単なるライブラリの更新ではなく、Stripe APIのバージョン自体を引き上げる作業でもありました。
この認識を持っていないと、レスポンス形状の変化に気づかないまま、テストを通過して本番に反映してしまう可能性があります。
- gemのCHANGELOGとStripe APIのchangelogを両方確認する
- stripe-mockでテストしている場合は、そのバージョンを追従させ、CIで差分を検出できる状態にしておく
- リクエスト側とWebhook側でAPIバージョンの扱いが異なることを意識する
- サンドボックス環境で実際の決済フローを動かして確認する
この4点を、次回以降のstripe gemアップデートでも意識していきたいと思います。
