🐡

Nuxt.js+LaravelでStripeのCheckoutの実装をやってみた【Stripe決済ページ遷移編】

2024/01/06に公開

概要

LaravelとNuxt.jsでStripeの決済処理を実装しました。
Stripeにはいくつか決済方法があるのですが今回はCheckoutと呼ばれる、Stripeが用意してくれた決済フォームを使用しました。
また、Checkoutにも2種類存在し、「決済時にStripeの決済ページに遷移する方法」と「自前のページに決済フォームを埋め込む方法」があるのですが、今回は「決済時にStripeの決済ページに遷移する方法」の紹介になります。
https://stripe.com/docs/payments/checkout

実装したもの

顧客が1つの商品を購入して完了するまでの実装をしました

https://youtu.be/ovSFHPwcZGY

事前準備

StripeのAPIキーの取得

以下を参考にAPIキーを取得してください。
https://stripe.com/docs/keys?locale=ja-JP#reveal-an-api-secret-key-for-test-mode

公開可能キーはフロントエンド側で使用するキー。
シークレットキーはバックエンド側で使用するAPIキー。

商品の追加

ダッシュボードの商品カタログから、購入してもらいたい商品を追加し、そのAPI IDをメモしておく。(バックエンドで使用する)

顧客アカウントの作成

誰が購入したかがわかるように、Stripeの顧客アカウントを作成する。
今回は記載していないが、Stripe APIを使用して顧客アカウントを作成も可能。

ダッシュボードの顧客より作成し、顧客IDをメモしておく。(バックエンドで使用する)

決済の簡単な流れ

  1. フロントがバックエンドのCheckoutセッション作成APIを叩く(フロント)
  2. バックエンドがstripeのセッション作成APIを叩き、その結果をフロントに返す(バックエンド)
  3. フロントがレスポンスのsessionIdを使用し、stripeの決済ページにリダイレクトする(フロント)
  4. 決済をし、任意のページにリダイレクト(フロント)

詳しくは以下をチェック↓
https://stripe.com/docs/payments/checkout/how-checkout-works?locale=ja-JP#lifecycle

バックエンドの実装(Laravel)

ライブラリを使用し、StripeのCheckoutセッション作成APIを叩き、その結果を返すAPIの作成をしました。

https://stripe.com/docs/api/checkout/sessions/create

ライブラリについて

stripe-phpという、 Stripe公式のphp用のライブラリを使用して実装しました。
採用理由としては、公式で信頼できるという点とドキュメントや使用例がたくさんあった点です。
https://github.com/stripe/stripe-php

Laravel CahierというLaravelが提供している別のライブラリも存在したのですが、こちらはドキュメントや使用例が少なく、サブスク支払がメイン機能そうだったので、今回は使用しませんでした。
https://readouble.com/laravel/9.x/ja/billing.html

重要なところの解説

$stripe->checkout->sessions->create()でStripeのCheckoutセッション作成APIを叩いています。以下にパラメーターについて解説します。

パラメーター 説明
line_items->price 顧客に購入してほしい商品のID。事前準備の商品IDを記載する
line_items->quantity 顧客に購入してもらう商品の個数
mode 今支払うか、後払いにするか、サブスクにするかを選択できる
customer Stripeの顧客アカウントID。誰が購入したかの把握ができる。事前準備の顧客IDを記載する
success_url 支払いに成功した時のリダイレクト先
cancel_url Stripeの決済ページの戻りボタンを押した時のリダイレクト先
automatic_tax->enable 税金の自動徴収をするかどうか。オンにすると価格1万円に設定した商品が、 税込の1万1千円で決済される
payment_method_options->card->setup_future_usage クレジットカードの情報を保存する。off_sessionにするとずっと保存してくれる
payment_method_types 支払い方法をどうするか。カード決済、ApplePayでの支払いなど選択できる
idempotency_key 多重決済を防ぐためのキー。 ユニークである必要がある。顧客が商品を購入する時の初回に作成し、それ以降はDBに保存されたこのキーを参照する

ソースコード

public function createCheckoutSession(): JsonResponse
    {
        /** @var string $config */
        $config = config('define.stripe.token');
        $stripe = new StripeClient($config);

        $checkout = $stripe->checkout->sessions->create([
            // 商品
            'line_items'             => [[
                'price'    => 'price_id',//商品ID
                'quantity' => 1,//個数
            ],
            ],
            'mode'                   => 'payment', // 支払いモード
            'customer'               => 'customer_id',//顧客ID 
            'success_url'            => 'http://localhost:8080/success,
            'cancel_url'             => 'http://localhost:8080/cancel', 
            // 税金を自動徴収するかどうか
            'automatic_tax'          => [
                'enabled' => true,
            ],
            // 支払い方法を保存するかどうか
            'payment_method_options' => [
                'card' => [
                    'setup_future_usage' => 'on_session',
                ],
            ],
            // 支払い方法
            'payment_method_types'   => ['card'],
        ],[
            'idempotency_key' => 'G5pobWIO8Q0ODYK1313333333',
        ]);
        return response()->json($checkout);
    }

フロントエンドの実装

ボタンを押したら、バックエンドのセッション作成のAPIを叩き、レスポンスのsessionIdを使用し、Stripeの決済ページにリダイレクトさせるような実装になっています。

stripe-jsでの実装

stripe-jsという、Stripeの公式のJavaScript用のライブラリを使用した実装方法の紹介です。
https://github.com/stripe/stripe-js

重要なところの解説

バックエンドからもらったclientSecretを使用し、ライブラリのredirectToCheckout()を呼べば、
Stripeの決済ページにリダイレクトします。

// Stripeのページにリダイレクトする
await stripe?.redirectToCheckout({
  sessionId: res.data.id,
})

ソースコード

<template>
  <div>
    <div>
      <button @click="submit">支払いをする</button>
    </div>
  </div>
</template>

<script lang="ts">
import Vue from 'vue'
import { StripeEmbeddedCheckout, loadStripe } from '@stripe/stripe-js'
import axios from 'axios'

export default Vue.extend({
  name: 'StripeTest',
  head: () => ({
    title: 'StripeTest | back check',
  }),
  components: {},
  data() {
    return {
      publishableKey: process.env.STRIPE_PUBLISHABLE_KEY,
      loading: false,
      sessionId: '',
      checkout: undefined as StripeEmbeddedCheckout | undefined,
    }
  },

  methods: {
    async submit() {
      const stripe = await loadStripe(
        process.env.STRIPE_PUBLISHABLE_KEY
          ? process.env.STRIPE_PUBLISHABLE_KEY
          : ''
      )

      await axios
        .post('http://localhost:8080/api/create_session')
        .then(async (res) => {
          // Stripeのページにリダイレクトする
          await stripe?.redirectToCheckout({
            sessionId: res.data.id,
          })
        })
    },
})
</script>

vue-stripeでの実装

vue-stripeとは、Stripeの認定パートナーのライブラリです。
ドキュメントが充実している。Checkoutで、Stripeの決済ページに遷移する方は実装できるが、自前のページに決済フォームを埋め込む方法は実装できません。
stripe-jsの方がコード量少ないので、個人的にはstripe-jsをお勧めします。

https://vuestripe.com

重要なところの解説

以下のように、ライブラリのコンポーネントを使用し、バックエンドからのsessionIdをコンポーネントに設定し、this.$refs.checkoutRef.redirectToCheckout();を呼び出すだけで、Stripeの決済ページに遷移する。

<stripe-checkout
      ref="checkoutRef"
      mode="payment"
      :pk="publishableKey"
      :session-id="sessionId"
      @loading="(v) => (loading = v)"
/>

ソースコード

<template>
  <div>
    <stripe-checkout
      ref="checkoutRef"
      mode="payment"
      :pk="publishableKey"
      :session-id="sessionId"
      @loading="(v) => (loading = v)"
    />
    <div>
      <button @click="submit">支払いをする</button>
    </div>
  </div>
</template>

<script lang="ts">
import Vue from 'vue'
import { StripeCheckout } from '@vue-stripe/vue-stripe'
import axios from 'axios'

export default Vue.extend({
  name: 'StripeTest',
  head: () => ({
    title: 'StripeTest | back check',
  }),
  components: {
    StripeCheckout,
  },
  data() {
    return {
      publishableKey: process.env.STRIPE_PUBLISHABLE_KEY,
      loading: false,
      sessionId: '',
    }
  },

  methods: {
    async submit() {
      await axios
        .post('http://localhost:8080/create_checkout_session')
        .then((res) => {
          this.sessionId = res.data.id
        })
        .then(() => {
          ;(this.$refs.checkoutRef as any).redirectToCheckout()
        })
    },
  },
})
</script>

終わりに

今回はStripeを使用し、決済ページに遷移するCheckoutの実装をやってみました。
Stripeの使用は初めてだったのですが、実装もそこまで難しなく、簡単に決済処理が作れて驚きでした。
ダッシュボードも使いやすかったので、決済の導入にはStripeをお勧めします。

Discussion