この記事は、Svelte Advent Calendar 2022 13日目の記事です。
Svelteは、WebアプリケーションやGUIを構築するためのUIライブラリの1つです。
Reactなどと異なり、仮想DOMを利用せず、軽量かつシンプルに実装できることを謳っています。
Svelteでアプリケーションを開発する場合、svelte-stripe
ライブラリを利用することで、Stripeでのオンライン決済機能の組み込みが簡単に行えます。
Viteでプロジェクトをセットアップする
早速Svelteアプリを作成しましょう。
今回はViteを利用します。
$ yarn create vite svelte-app --template svelte-ts
..
Scaffolding project in /Users/sandbox/svelte-app...
Done. Now run:
cd svelte-app
yarn
yarn dev
✨ Done in 3.34s.
完了メッセージに表示されたコマンドを実行して、セットアップされたアプリを起動しましょう。
$ cd svelte-app
$ yarn
$ yarn dev
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_...
Stripe用のコンポーネントファイルを作成
Stripeに関するリソースをまとめるファイル・コンポーネントを用意しましょう。
今回は、src/lib/Stripe.svelte
ファイルを作成しました。
<script>
import { loadStripe } from '@stripe/stripe-js'
import { Elements } from 'svelte-stripe'
import { onMount } from 'svelte';
let stripe = null
onMount(async () => {
stripe = await loadStripe(import.meta.env.VITE_STRIPE_PUBLIC_KEY)
})
</script>
{#if stripe}
<Elements {stripe}>
<!-- this is where your Stripe components go -->
<b>Hello Stripe</b>
</Elements>
{/if}
これをsrc/App.svelte
で読み込みます。
<script lang="ts">
import svelteLogo from './assets/svelte.svg'
import Counter from './lib/Counter.svelte'
+ import StripeFrom from './lib/Stripe.svelte'
</script>
...
<div class="card">
<Counter />
+ <StripeFrom />
</div>
カウンターの横に、「Hello Stripe」が表示されていれば、追加成功です。
Stripeの決済フォームを描画する
Stripe組み込みの準備ができましたので、決済フォームを表示させましょう。
Svelteにはサーバー側の機能がないため、Stripeのクイックスタートなどで別途Payment Intentを作成するAPIを用意します。
続いてコンポーネント内のコードを変更します。
<script>
import { loadStripe } from '@stripe/stripe-js'
- import { Elements } from 'svelte-stripe'
+ import { Elements, PaymentElement } from 'svelte-stripe'
import { onMount } from 'svelte';
let stripe = null
+ let clientSecret = ''
+ let elements
onMount(async () => {
stripe = await loadStripe(import.meta.env.VITE_STRIPE_PUBLIC_KEY)
+ const response = await fetch('http://localhost:3100/stripe', {
+ method: 'POST'
+ })
+ const result = await response.json()
+ clientSecret = result.client_secret // クイックスタートの場合、「result.clientSecret」
})
</script>
-{#if stripe}
+{#if stripe && clientSecret}
- <Elements {stripe}>
+ <Elements {stripe} {clientSecret} bind:elements>
+ <PaymentElement />
</Elements>
{/if}
まず、onMount
にてPayment Intentを作成するAPIを呼び出し、ClientSecretを取得しています。
次に、取得したClientSecretを利用して、PaymentElementを表示させています。
最後に、Elementsをelements
変数にbindして、この後のsubmitイベントに備えています。
変更を保存すると、決済フォームが画面に表示されます。
決済フォームのSubmit処理を実装する
最後に、決済を完了するためのイベントを実装します。
以下の関数をStripe.svelte
に追加しましょう。
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')
}
}
続いて、Stripe.svelte
のHTMLを以下のように変更します。
- <Elements {stripe} {clientSecret} bind:elements>
- <PaymentElement />
- </Elements>
+ <form on:submit|preventDefault={submit}>
+ <Elements {stripe} {clientSecret} bind:elements>
+ <PaymentElement />
+ <button type='submit'>Pay now</button>
+ </Elements>
form
タグを追加し、on:submit
でフォームのsubmitイベントを設定しました。
これでフォームにボタンが追加され、決済を完了できるようになります。
Stripeが用意している「テストカード番号」を利用して、決済をテストしましょう。
成功メッセージが表示されれば、実装完了です。
追加の学習リソース
PaymentElementを利用しない場合の、クレジットカード以外の実装方法などについては、公式のサンプルを参考にできます。
コンビニ決済やApple Pay/Google Payなどもサポートされています。
SvelteKitを利用して、Payment IntentやSetup Intentを作成する方法やWebhook APIを実装する方法なども紹介されています。