Why not login to Qiita and try out its useful features?

We'll deliver articles that match you.

You can read useful information later.

0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Next.js 14 で Stripe サブスクリプションを実装する

Posted at

こんばんは。

今日は「Next.js 14 で Stripe サブスクリプションを実装する方法」について説明します。

Next.js 14 で Stripe サブスクリプションを実装する方法について、フロントエンドとバックエンドの両方で必要な手順とコード例を以下に示します。フロントエンドでは、カード番号、CVC、有効期限、および顧客名を含む支払いフォームを作成し、バックエンドでは Next.js API を使用して Stripe サブスクリプションを管理します。

必要なパッケージのインストールと環境変数の設定

パッケージのインストール

まず、Stripe の公式ライブラリと必要なパッケージをインストールします。

npm install @stripe/stripe-js @stripe/react-stripe-js stripe
  • @stripe/stripe-js@stripe/react-stripe-js: フロントエンドで Stripe Elements を使用するためのライブラリ。
  • stripe: バックエンドで Stripe API を操作するためのライブラリ。

環境変数の設定

プロジェクトのルートに .env.local ファイルを作成し、以下の環境変数を設定します。

NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=your_publishable_key_here
STRIPE_SECRET_KEY=your_secret_key_here
  • NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY: フロントエンドで使用する公開可能キー。
  • STRIPE_SECRET_KEY: バックエンドで使用する秘密キー。

実装

フロントエンドの実装

フロントエンドでは、Stripe Elements を使用して安全な支払いフォームを作成します。

Stripe プロバイダーの設定

_app.js または _app.tsx ファイルで Elements プロバイダーを設定します。

// pages/_app.js
import { Elements } from '@stripe/react-stripe-js';
import { loadStripe } from '@stripe/stripe-js';
import '../styles/globals.css';

const stripePromise = loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY);

function MyApp({ Component, pageProps }) {
  return (
    <Elements stripe={stripePromise}>
      <Component {...pageProps} />
    </Elements>
  );
}

export default MyApp;

支払いフォームの作成

pages/subscribe.js ファイルを作成し、支払いフォームを実装します。

// pages/subscribe.js
import { useState } from 'react';
import {
  CardCvcElement,
  CardExpiryElement,
  CardNumberElement,
  useElements,
  useStripe,
} from '@stripe/react-stripe-js'

const Subscribe = () => {
  const stripe = useStripe();
  const elements = useElements();
  
  const [customerName, setCustomerName] = useState('');
  const [email, setEmail] = useState('');
  const [subscriptionStatus, setSubscriptionStatus] = useState(null);
  const [error, setError] = useState(null);

  const handleSubmit = async (e) => {
    e.preventDefault();
    
    if (!stripe || !elements) {
      return;
    }

    const cardNumberElement = elements.getElement(CardNumberElement)
    const cardExpiryElement = elements.getElement(CardExpiryElement)
    const cardCvcElement = elements.getElement(CardCvcElement)

    if (!cardNumberElement || !cardExpiryElement || !cardCvcElement) {
      console.error('Stripe Elements not found')
      return
    }

    try {
      const { error, paymentMethod } = await stripe.createPaymentMethod({
        type: 'card',
        card: cardNumberElement,
        billing_details: {
          name: cardholderName, // Pass the cardholder name here
        },
      })

      if (error) return

      // 顧客情報と支払い情報をバックエンドに送信
      const response = await fetch('/api/subscribe', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          name: customerName,
          email: email,
          paymentMethodId: paymentMethod.id,
        }),
      });
      
      const result = await response.json();

      if (result.error) {
        setError(result.error);
      } else {
        setSubscriptionStatus(result.status);
      }
    } catch (e) {
      console.error(e)
    }
  };

  return (
    <div>
      <h1>サブスクリプション登録</h1>
      <form onSubmit={handleSubmit}>
        <div>
          <label>名前</label>
          <input
            type="text"
            value={customerName}
            onChange={(e) => setCustomerName(e.target.value)}
            required
          />
        </div>
        <div>
          <label>メールアドレス</label>
          <input
            type="email"
            value={email}
            onChange={(e) => setEmail(e.target.value)}
            required
          />
        </div>
        <div>
          <label>カード情報</label>
          <CardNumberElement />
        </div>
        <div>
          <label>有効期限</label>
          <CardExpiryElement />
        </div>
        <div>
          <label>セキュリティコード</label>
          <CardCvcElement />
        </div>
        <button type="submit" disabled={!stripe}>
          購入
        </button>
      </form>
      {subscriptionStatus && <p>サブスクリプションが正常に作成されました</p>}
      {error && <p style={{ color: 'red' }}>{error}</p>}
    </div>
  );
};

export default Subscribe;

フォーム送信時にバックエンド API /api/subscribe に顧客情報と支払い情報を送信します。

バックエンドの実装

Next.js の API Routes を使用して、サブスクリプションの作成を処理します。

Stripe インスタンスの設定

lib/stripe.js ファイルを作成し、Stripe インスタンスを設定します。

// lib/stripe.js
import Stripe from 'stripe';

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY, {
  apiVersion: '2022-11-15',
});

export default stripe;

サブスクリプション API の作成

pages/api/subscribe.js ファイルを作成し、サブスクリプションの作成を処理します。

// pages/api/subscribe.js
import stripe from '../../lib/stripe';

export default async function handler(req, res) {
  if (req.method === 'POST') {
    const { name, email, paymentMethodId } = req.body;

    try {
      // 顧客の作成
      const customer = await stripe.customers.create({
        name: name,
        email: email,
        payment_method: paymentMethodId,
        invoice_settings: {
          default_payment_method: paymentMethodId,
        },
      });

      // サブスクリプションの作成
      const subscription = await stripe.subscriptions.create({
        customer: customer.id,
        items: [{ price: PRICE_ID }], // 事前にStripeダッシュボードで作成した価格IDに置き換えてください
        expand: ['latest_invoice.payment_intent'],
      });

      res.status(200).json({ status: subscription.status });
    } catch (error) {
      res.status(400).json({ error: error.message });
    }
  } else {
    res.setHeader('Allow', 'POST');
    res.status(405).end('Method Not Allowed');
  }
}
  • サブスクリプションの作成: 作成した顧客に対してサブスクリプションを作成します。PRICE_ID(price_XXXXXXXXXX) は事前に Stripe ダッシュボードで設定した価格 ID に置き換えてください。
  • エラーハンドリング: エラーが発生した場合、クライアントにエラーメッセージを返します。

以上が Next.js 14 で Stripe サブスクリプションを実装する基本的な手順とコード例です。詳細なカスタマイズや高度な機能については、Stripe の公式ドキュメントを参照してください。

追加の考慮事項

  • セキュリティ: 支払い情報は Stripe Elements を使用して安全に処理されますが、常に最新のセキュリティベストプラクティスに従ってください。
  • エラーハンドリング: フロントエンドとバックエンドの両方で適切なエラーハンドリングを実装し、ユーザーにわかりやすいフィードバックを提供してください。
  • サブスクリプション管理: ユーザーがサブスクリプションを管理(キャンセル、更新など)できるように、追加の機能を実装することを検討してください。

今日は以上です。

ありがとうございました。
よろしくお願いいたします。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up

Qiita Advent Calendar is held!

Qiita Advent Calendar is an article posting event where you post articles by filling a calendar 🎅

Some calendars come with gifts and some gifts are drawn from all calendars 👀

Please tie the article to your calendar and let's enjoy Christmas together!

0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?