Supabase Wrapperを使ってStripeのデータにSupabaseからアクセスする

[Supabase](https://supabase.com/)はPostgresが裏側にくっついているバックエンドサービスです。Supabaseとお気に入りのフロントエンドフレームワークを持ち寄るだけで簡単にアプリが作れます。SupabaseのPostgresデータベースに保存されているデータは管理画面から簡単に閲覧することができます。

そんなSupabaseには[Foreign Data Wrappers](https://supabase.com/docs/guides/database/extensions/wrappers/overview)という機能があります。これは例えばStripeやFirebaseなどのSupabaseではない外部サービスのデータをさもSupabaseのテーブルの一部であるかのような感覚で取り扱える様になる機能で、管理画面から外部サービスのデータを見ることができるだけでなく、データの挿入・更新・削除もでき、また [Postgres Functions](https://supabase.com/docs/guides/database/functions)を使うことでクライアント側からもそれらのデータをSupabaseのデータと同じように取り扱うことができる様になる機能です。

今回は、そんなSupabase Wrappersを使って実際にStripeのデータでこんなことができるんだよっていうユースケースをいくつか紹介しようと思います。

## 前提

今回はStripeとSupabaseを繋いで色々遊んでいくのですが、その前にSupabaseとStripeに多少データが入っていないと遊びようがないですよね。実は、Stripe, Supabase, そしてNext.jsを使って簡単にSaaSアプリが構築できるテンプレートがVercelから出されています。

https://vercel.com/new/templates/next.js/subscription-starter

今回はこちらを使って一通りStripe内に商品情報や顧客情報などが入っているところからスタートしたいと思いますので、もし一緒にWrapperを触ってみたい人は一度上記の subscription starterテンプレートを触ってみてください！

## StripeとSupabaseを紐付け

Supabase Wrappersを使える様になる前にまず簡単な設定が必要になります。Supabaseの管理画面から`Database -> Wrappers`と進んで右上にある緑色の`Add wrapper`ボタンを押しましょう。いろんなwrapperの選択肢が出てきますが、今回はStripeを選びます。

![Screenshot 2023-12-15 at 18.21.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/187071/919def3b-c14b-f9d9-a3db-df5b336fb38c.png)

次の画面で`Wrapper Name`はこのwrapperの内部名を与えます。今回はStripeの開発環境に試しに繋ぐということで`Stripe dev`と名付けましょう。`Stripe Secret Key`はStripeの管理画面から取得してくるAPIキーです。

![Supabase Wrappers dashboard](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/187071/9d671881-8e38-1031-a76e-4275592ee0b6.png)

最後に追加したいテーブルを設定していきます。`Add foreign table`ボタンを押してテーブルを設定していきます。

まず、`stripe`というスキーマを作りましょう。そしてその中に`subscriptions`, `customers`, `prices`, `products`を追加します。

![Screenshot 2023-12-15 at 18.40.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/187071/bb61afa3-73ba-8d9a-9782-2ad7d7a1d841.png)

そうするとこのようにTable Editorの画面から`stripe`スキーマを覗くことで各種Stripeのデータが見える様になっていると思います。

![Screenshot 2023-12-15 at 18.45.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/187071/08a0bc3e-65e7-c364-67b2-5e0677fc5dce.png)

準備が整ったので、ここからはSQLエディターに移動してそこで実際に色々クエリーを叩いてみましょう。

## ユースケース1：各Supabaseユーザーに対応するStripeの顧客IDを取得する

まずは比較的シンプルな例から見てみましょう。ここではSupabaseのユーザー一覧とそれらに対応するStripeの顧客IDを引っ張ってきています。この様にWrapperを使って外部のデータを使ってSupabase内のデータとjoinすることだって可能なんです！

```sql
-- Stripeの顧客とSupabaseのユーザーを紐づけて閲覧する
select 
  u.id as id,
  c.id as stripe_id
from auth.users u
inner join stripe.customers c
  on u.id = ((c.attrs->'metadata'->>'supabaseUUID')::uuid);
```

## ユースケース2：Stripeに新しい顧客を追加

次はWrapperを使ってStripeに新しい顧客を追加してみましょう。実際には、subscription-starterのテンプレートを使っている際はSupabase側で新規ユーザーが作成されたタイミングでStripe側の顧客が作成されるので、下記のようなコードを走らせる必要はないのですが、Wrapperを使ってデータの挿入もできちゃうんですってところを確認するためにやってみましょう。

```sql
-- Stripeに新しい顧客を追加する
insert into stripe.customers
  (email)
  values ('new@example.com');
```

以上のコードをSQLエディターで走らせてからStripeの管理画面に行くと実際に新規ユーザーが作成されているのがわかると思います。

## ユースケース3：商品名を変更する

一個前の例ではinsertをしたので、今度はupdateをしてみましょう。以下のクエリーで新しい商品をStripe内に作ることができます。Supabaseのrpcを使えばクライアント側からもこちらのコードを呼び出せるのでいろいろできることの幅が広がりそうですよね！

```sql
-- Stripeの商品情報を編集する
update stripe.products
  set name = 'Enterprise'
  where name = 'Team';
  ```

## ユースケース4：顧客の購買情報を閲覧する

最後にもう少し色々joinしている例を見てみましょう。以下のクエリーをSQLエディターで走らせると特定のSupabaseユーザーがいくらのプランを購読中かわかります。

```sql
-- 顧客の購読情報を閲覧する
select 
  auth.users.id as id,
  prices.currency,
  prices.unit_amount
from auth.users
inner join stripe.customers
  on users.id = ((customers.attrs->'metadata'->>'supabaseUUID')::uuid)
inner join stripe.subscriptions
  on customers.id = subscriptions.customer
inner join stripe.prices
  on subscriptions.attrs->'plan'->>'id' = prices.id
where users.id = 'a1807997-0e7a-4954-9557-0a2c66d69380'::uuid; -- ここには実在する特定のSupabaseユーザーのユーザーIDを入れる
```

この様にこのユーザーは$500のプランを購読中であることがわかります。

![Screenshot 2023-12-15 at 18.57.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/187071/eec59f96-26aa-54a4-cdfb-eb382aa357d3.png)

## まとめ

今回はSupabaseのForeign Data Wrapperで遊んでみるをテーマにStripeとsupabaseを繋げていろんな形で双方のデータとやり取りをしてみました。Foreign data wrapperを使うとあまりAPIを意識せずに複数サービスを繋げたサービスが構築できそうですね！ぜひ皆さんもいろいろ試してみてください！