Stripe の新しい Embedded Checkout を試してみた
この記事は JP_Stripes Advent Calendar 2023 の 5 日目の記事です。前回の記事は hidetaka okamoto さんによるStockifyアプリで、Stripeに在庫管理機能を追加するでした。
弊社のシステムでは Stripe Checkout Session をサーバーサイドで作成し、クライアントサイドに Checkout Session ID を渡し、Stripe.js の redirectToCheckout メソッドを利用して Stripe Checkout のサイトにリダイレクトしていたのですが、その方法は Deprecated になってしまっていたようでした。
代わりに現在推奨されるのは、下記の二つの方法です。
- Stripe Checkout Session を作成したときに返却される
url
パラメータに(何らかの方法で)ユーザーをリダイレクトさせる - Stripe Checkout Session を
ui_mode: 'embedded'
で作成し、返却されるclient_secret
値をフロントエンドに渡し、フロントエンドはそれを使い Checkout ページを iframe で表示させる
前者の方法は以前から利用できましたが、後者は比較的新しい方法だと思います。日本語の情報もほとんどなさそうだったので、今回はこちらを試してみることにしました。
/** @jsx jsx */
import { Stripe } from 'npm:stripe';
import { Hono } from 'https://deno.land/x/hono@v3.10.4/mod.ts'
import { jsx } from 'https://deno.land/x/hono@v3.10.4/middleware.ts'
import { html } from "https://deno.land/x/hono@v3.10.4/helper/html/index.ts";
const stripe = new Stripe('<Stripe シークレットキー>', { apiVersion: '2023-10-16' });
const app = new Hono();
app.get('/', async (c) => {
const checkoutSession = await stripe.checkout.sessions.create({
mode: 'payment',
line_items: [{
price_data: {
currency: 'JPY',
unit_amount: 100,
product_data: {
name: 'テスト',
},
},
quantity: 1,
}],
ui_mode: 'embedded',
redirect_on_completion: 'if_required',
return_url: 'http://localhost:8000',
});
return c.html(<html>
<script src="https://js.stripe.com/v3/"></script>
{html`
<script type="module">
const checkout = await Stripe('<Stripe 公開可能キー>').initEmbeddedCheckout({
clientSecret: '${checkoutSession.client_secret}',
onComplete: () => alert('Success'),
});
checkout.mount('#checkout');
</script>
`}
↓↓↓IFRAME↓↓↓
<div id="checkout"></div>
↑↑↑IFRAME↑↑↑
</html>);
});
Deno.serve(app.fetch);
これを index.tsx
として保存し、deno run -A index.tsx
で実行しました。
するとこんな感じで Checkout Session が iframe として表示され決済できました。
気づいた点は下記です。
- 最新の API では、
line_items: [{ amount: 100, currency: 'JPY' }]
みたいな方法が使えなくなっていて、ちゃんと Price を作らないといけない- 毎回金額が変わるような用途では無限に Price が増えてしまう…?と思ったら作られてなさそうだった。
price_data
を指定しても恒久的に作成されるわけではない?
- 毎回金額が変わるような用途では無限に Price が増えてしまう…?と思ったら作られてなさそうだった。
- Stripe にリダイレクトするわけではないので、
success_url
やcancel_url
は要らない(指定するとエラーになる) - 代わりに
return_url
もしくはredirect_on_completion: 'never'
の指定が必要になる: https://stripe.com/docs/payments/checkout/custom-redirect-behavior
解消していない疑問点です:
redirect_on_completion: 'if_required'
はどんなときにリダイレクトするのか?例えば 3D Secure とか?redirect_on_completion: 'never'
としたときにリダイレクトが必要になった場合はどうなるのか?redirect_on_completion: 'never'
としたときにフロントエンドで決済の完了を知る方法が分からなかった
(今後分かったことがあればここに追記したいと思います)
SPA だとできる限りページの読み込み直しは減らしたいと思うので、そういう場合に iframe だと便利ですね。
今回のコードは Gist にもアップしたのでそちらでも見ることができます。また、下記のコマンドで直接実行することもできます。
deno run https://gist.githubusercontent.com/acomagu/2a55aca48a45c17f36a71fceec6b87a1/raw/try-stripe-embedded-checkout.tsx
(API キーの取得のために Stripe コマンドを実行します)
ありがとうございました!