SupabaseとStripeを連携させるNext.jsのサンプルアプリをローカル環境で動かしてみた
この記事は、Supabase Advent Calendar 2023の1日目の記事です。SupabaseとStripeを組み合わせて動かせるサンプルを探したところ、Vercelに「SupabaseとStripeを使ったサブスクリプション決済のサンプル」を見つけました。記事では、Supabaseのセットアップ方法やデータベーステーブルの作成、ログインユーザーの作成、Vercelのサンプルアプリのダウンロード方法などが紹介されています。さらに、StripeとSupabaseへの環境変数の設定やWebhookの連携方法、料金の登録方法なども説明されています。最後に、申し込みの手順と結果の確認方法も紹介されています。
目次
この記事は「Supabase Advent Calendar 2023」1日目の記事です。
先日(といっても9月なので結構前ですが)SupabaseのTylerさんにお声がけ頂いて、Supabase & Stripeの開発者イベントを開催しました。

その際、SupabaseとStripeを組み合わせて動かせるサンプルを探したところ、なんとVercelに「SupabaseとStripeを使ったサブスクリプション決済のサンプル」というど真ん中のサンプルを見つけました。

「これは触るしかない!」となって触った時のスクリーンキャプチャとコードメモを、記事としてまとめました。
Supabaseのセットアップ
Supabaseのアカウントを作成したので、早速セットアップしていきます。なお、Stripeについてはすでに取得済みとして端折ります。
Supabaseのprojectを作成
まずプロジェクトを作成します。今回は[+ New Project]で新規作成しました。

プロジェクト名・DBパスワードとリージョンを指定しましょう。

作成完了すると、APIキーなどが取得できます。

データベーステーブルを作成する
サンプルアプリで利用するテーブルを作成しましょう。リポジトリ内にあるschema.sql
の内容をコピーして、SQL Editorに貼り付けます。

[Run]ボタンを押して実行すると、テーブルが5つ作成されます。

ブラウザ上でこうやってDBを操作できるのは、なかなか新鮮な体験ですね。
アプリにログインするユーザーを作成する
続いてログインユーザーを作成しておきます。
[Authentication]ページに移動しましょう。

[Add user]ボタンをクリックすると、選択肢が表示されます。

[Create new user]を選んで、ユーザー名とパスワードを入力するフォームを開きます。

これでログイン用のユーザーが登録できました。
サンプルアプリを、ローカルにダウンロードする
続いてVercelのサンプルアプリを、ローカル環境で動かすためにダウンロードしましょう。

Next.jsアプリケーションですので、次の3コマンドで利用しているライブラリなどのインストールまで済ませます。
$ git clone https://github.com/vercel/nextjs-subscription-payments
$ cd nextjs-subscription-payments/
$ npm install
続いて環境変数を管理するファイルをコピーしましょう。
% cp .env.local.example .env.local
環境変数は、StripeとSupabaseそれぞれから取得します。
# Update these with your Supabase details from your project settings > API
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=
SUPABASE_SERVICE_ROLE_KEY=
# Update these with your Stripe credentials from https://dashboard.stripe.com/apikeys
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_1234
STRIPE_SECRET_KEY=sk_test_1234
STRIPE_WEBHOOK_SECRET=whsec_1234
# Update this with your stable site URL only for the production environment.
NEXT_PUBLIC_SITE_URL=https://your-deployment-url.vercel.app
StripeのAPIキーは、STRIPE_SECRET_KEY
が「シークレットキー」、NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY
が「公開可能キー」です。ダッシュボードから取得してそれぞれ設定しましょう。

Supabase側も、API Settingsページから必要なURLやキーをコピーアンドペーストしてきます。

STRIPE_WEBHOOK_SECRET
については、ローカルで試す場合は1工夫必要です。Stripe CLIを利用して、StripeのWebhookイベントをローカルに中継するようにしましょう。その際にwhsec_
から始まるシークレットが発行されますので、これを環境変数に設定します。
% stripe listen --forward-to http://localhost:3000/api/webhooks
> Ready! You are using Stripe API Version [2023-08-16]. Your webhook signing secret is whsec_xxxxxx (^C to quit)
サブスクリプションのプラン情報などを、Stripe / Supabaseに登録する
プラン・料金データの投入は、StripeとSupabaseそれぞれに行います。ただし個別にAPIやSQLを実行するのではなく、Stripe Webhookを利用して、StripeからSupabaseにデータを連携させる方法をとります。
サンプルで実装されているWebhook APIが必要です。そのため、npm run dev
またはnext dev
コマンドを実行して、アプリケーションを起動させましょう。
% npm run dev
- ready started server on 0.0.0.0:3000, url: http://localhost:3000
続いてstripe listen --forward-to http://localhost:3000/api/webhooks
を実行中に、以下のコマンドを動かしましょう。stripe fixtures
は、読み込ませたJSONファイルに定義されているAPIリクエストをまとめて実行するコマンドです。
% stripe fixtures fixtures/stripe-fixtures.json
Stripe上に商品と料金データが複数生成されていることが、コマンドラインに表示されます。
Setting up fixture for: prod_hobby
Running fixture for: prod_hobby
Setting up fixture for: price_hobby_month
Running fixture for: price_hobby_month
Setting up fixture for: price_hobby_year
Running fixture for: price_hobby_year
Setting up fixture for: prod_freelancer
Running fixture for: prod_freelancer
Setting up fixture for: price_freelancer_month
Running fixture for: price_freelancer_month
Setting up fixture for: price_freelancer_year
Running fixture for: price_freelancer_year
Stripe Webhookを正しく連携できていれば、Stripeにデータを登録後にWebhoo経由でSupabaseにもデータが投入されています。
アプリをローカルで起動する
データの投入が終わったので、http://localhost:3000 にアクセスしてみましょう。
もし下の画像のように、「No subscription pricing plans found」と出た場合は、Supabaseへのデータ連携がうまく行っていない可能性があります。stripe fixtures
コマンドを実行するステップに戻り、Webhookが正しく連携できているかなどを確認しましょう。

正しく実装・連携できていれば、料金表が表示されます。

ログイン画面から、事前にSupabaseダッシュボードで作成したユーザー情報でログインしましょう。

マイページには、Stripeのカスタマーポータルへのリンクボタンも用意されています。

サブスクリプションを申し込みしてみる
せっかくなので、申し込みもやってみましょう。

Subscribe
ボタンをクリックすると、Stripe Checkoutの申し込みページが開きます。メールアドレスはSupabaseのユーザー情報がStripeに共有されているため、入力する必要はありません。テストモードであれば、Stripeが用意するテストのカード番号を利用して、申し込みを済ませましょう。

申し込み完了後、マイページに移動すると契約中のプランが選択したものに変わります。

またSupabaseのDBにもサブスクリプションなどのレコードが追加されています。

触ってみた感想
ほとんど出来上がっているテンプレートを使っただけではありますが、Stripeにはないけれどもアプリケーション開発に欠かせない「認証」と「データベース」の2つが簡単に手に入るのはかなり魅力的だなと思いました。
イベント当日に存在を知った「Stripe Wrapper」を使えば、Webhook連携も最小限にできる・・・気がしますので、これもまた試してみたいと思います。