この記事は、SvelteKit Advent Calendar 2022 14日目の記事です。
SveltKitはSvelteでアプリケーションを構築するためのフレームワークです。
2022/11時点では、まだVersion1.0.0がリリースされていませんが、Svelteを使う上では注目しておきたいフレームワークではないかと思います。
この記事では、svelte-stripe
ライブラリを利用して、SveltKitでサブスクリプション申込のUI / APIを実装する方法を紹介します。
SvelteKitプロジェクトをセットアップする
セットアップは、以下のコマンドで開始します。
$ npm create svelte@latest sveltekit-app
テンプレートを利用するかどうかや、TypeScript, ESLint, Prettier, Playwriteを利用するかを聞かれます。
? Which Svelte app template? › - Use arrow-keys. Return to submit.
❯ SvelteKit demo app - A demo app showcasing some of the features of SvelteKit - play a word guessing game that works without JavaScript!
Skeleton project
Library skeleton project
今回は、以下の設定でセットアップしました。
✔ Which Svelte app template? › SvelteKit demo app
✔ Add type checking with TypeScript? › Yes, using TypeScript syntax
✔ Add ESLint for code linting? … No / Yes
✔ Add Prettier for code formatting? … No / Yes
✔ Add Playwright for browser testing? … No / Yes
Next steps
が表示されれば、セットアップ完了です。
Next steps:
1: cd sveltekit-ap
2: npm install (or pnpm install, etc)
3: git init && git add -A && git commit -m "Initial commit" (optional)
4: npm run dev -- --open
To close the dev server, hit Ctrl-C
Stuck? Visit us at https://svelte.dev/chat
指示に従ってコマンドを実行しましょう。
$ cd sveltekit-app
$ npm install (or pnpm install, etc)
$ git init && git add -A && git commit -m "Initial commit"
$ npm run dev -- --open
セットアップに成功していれば、デモアプリが立ち上がります。
svelte-stripeでStripeの決済フォームを組み込む
セットアップが完了しましたので、Stripeの組み込みを行いましょう。
今回はコミュニティライブラリのsvelte-stripeを利用します。
ライブラリのインストール
まずはライブラリをインストールしましょう。
$ yarn add stripe svelte-stripe
環境変数の設定
StripeのAPIキーを.env.local
ファイルに保存しましょう。
VITE_STRIPE_PUBLIC_KEY=pk_test_...
STRIPE_SECRET_KEY=sk_test_...
ページ読み込み時に、Subscriptionデータを生成する
SvelteKitがページを読み込む際に、サーバー側でサブスクリプションデータを生成させます。
src/routes/subscription/+page.server.ts
ファイルを作成し、以下のコードを追加しましょう。
import { STRIPE_SECRET_KEY } from '$env/static/private';
import Stripe from 'stripe';
/** @type {import('./$types').PageServerLoad} */
export async function load() {
const stripe = new Stripe(STRIPE_SECRET_KEY, {
apiVersion: '2022-11-15'
});
const customer = await stripe.customers.create()
const product = await stripe.products.create({
name: 'SvelteKitデモ用'
})
const subscription = await stripe.subscriptions.create({
customer: customer.id,
items: [{
price_data: {
unit_amount: 1000,
currency: 'jpy',
recurring: {
interval: 'month',
},
product: product.id
}
}],
payment_behavior: 'default_incomplete',
expand: ['latest_invoice.payment_intent'],
payment_settings: {
save_default_payment_method: 'on_subscription',
},
})
return {
subscriptionId: subscription.id,
clientSecret: ((subscription.latest_invoice as Stripe.Invoice).payment_intent as Stripe.PaymentIntent).client_secret
}
}
Subscription作成処理の参考
今回のサンプルコードは、事前にダッシュボードでデータを作成する必要のないように用意しました。
事前準備が不要な代わりに、ページ読み込みの度にCustomerや商品データが生成されますのでご注意ください。
引数の解説等については、以下の記事で紹介しています。
生成したSubscriptionデータを元に、決済フォームを表示する
続いて決済フォームを表示させましょう。
src/routes/subscription/+page.svelte
を作成します。
<script lan="ts">
/** @type {import('./$types').PageData} */
import { loadStripe } from '@stripe/stripe-js'
import { Elements, PaymentElement } from 'svelte-stripe'
import { onMount } from 'svelte';
import { PUBLIC_STRIPE_PUBLIC_KEY } from '$env/static/public';
export let data
export const { clientSecret } = data
let stripe = null
let elements
onMount(async () => {
stripe = await loadStripe(PUBLIC_STRIPE_PUBLIC_KEY)
})
</script>
<div>
<h1>hello</h1>
{#if stripe && clientSecret}
<form>
<Elements {stripe} {clientSecret} bind:elements>
<PaymentElement />
<button type='submit'>Subscribe</button>
</Elements>
</form>
{/if}
</div>
http://localhost:5173/subscription にアクセスして、決済フォームが表示されれば成功です。
実際の組み込みでは、契約内容(料金・期間など)を表示する必要がある点にご注意ください。
サブスクリプションの申込処理を完了する
あとはformのsubmit処理を追加して、申し込みを完了させるだけです。
先ほど作成した+page.svelte
を編集して、submit処理を追加しましょう。
<script lan="ts">
/** @type {import('./$types').PageData} */
import { loadStripe } from '@stripe/stripe-js'
import { Elements, PaymentElement } from 'svelte-stripe'
import { onMount } from 'svelte';
import { PUBLIC_STRIPE_PUBLIC_KEY } from '$env/static/public';
export let data
export const { clientSecret } = data
let stripe = null
let elements
onMount(async () => {
stripe = await loadStripe(PUBLIC_STRIPE_PUBLIC_KEY)
})
+ async function submit() {
+ if (!stripe || !elements) {
+ throw new Error('stripe or elements not defined')
+ }
+ const { error, paymentIntent } = await stripe.confirmPayment({
+ elements,
+ redirect: 'if_required'
+ })
+ if (error) {
+ window.alert(JSON.stringify(error))
+ } else {
+ window.alert('done')
+ }
+ }
</script>
続いてformタグを編集し、submitイベントを設定します。
- <form>
+ <form on:submit|preventDefault={submit}>
Stripeが用意している「テストカード番号」を利用して、決済をテストしましょう。
成功メッセージが表示されれば、実装完了です。
Stripeの料金表を使って、手早く組み込む方法
ここまで決済フォームを埋め込む方法を紹介しましたが、Stripeでは料金表そのものを埋め込むことも可能です。
ダッシュボードで生成した料金表の、コードスニペットを埋め込むだけで実装できますので、手軽に実装できます。
<div class="text-column">
<h1>料金表</h1>
</div>
<script async src="https://js.stripe.com/v3/pricing-table.js"></script>
<stripe-pricing-table
pricing-table-id="prctbl_xxxx"
publishable-key="pk_test_xxxxx">
</stripe-pricing-table>