Stripeを使ってReactに決済機能を実装する

# はじめに
Reactで作成したWebサービスに、Stripeというサービスを使って決済機能を実装する方法を紹介します。
今回は、Stripeで用意されている支払ページに遷移させて、決済を実施する機能を実装していきます。
https://stripe.com/docs/checkout/integration-builder

# 環境/前提
![<LABEL>-<MESSAGE>](https://img.shields.io/badge/node-14.15.0-<COLOR>) ![<LABEL>-<MESSAGE>](https://img.shields.io/badge/npm-6.14.8-<COLOR>) 

- 上記ライブラリがインストールされていること。

# 手順

## Stripeのアカウント作成
Stripeは、スタートアップから大規模企業までが活用しているオンライン決済サービスです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502798/20671944-60f0-84c9-3c32-7ddc61e72a12.png)

下記リンクからStripeにアクセスし、アカウント登録をしていきましょう。

https://stripe.com/jp
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502798/8b3a2d0a-59e6-f09e-f176-b67aaf9f57c4.png)

任意のアカウント名を入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502798/cb8fafa7-1061-bd7f-1f6d-422c0779ede7.png)

アカウントの登録が完了すると、下記のようなダッシュボードが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502798/231cef25-383b-dfe9-49a5-bff42a83fc5a.png)

## StripeにアクセスするためのAPIキーを確認
次に、アプリからStripeにアクセスするためのAPIキーを確認しましょう。
左ペインの「開発者」>「APIキー」から確認できます。

![スクリーンショット 2021-04-22 085103.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502798/e6cda89f-8809-4919-1774-9c9147425998.png)

公開可能キーとシークレットキーには、下記の違いがあります。
>公開可能 API キーは、Stripe でお使いのアカウントを識別する目的のみに使用され、シークレットではありません。すなわち、Stripe.js JavaScript コードや Android または iPhone アプリで安全に公開可能です。
シークレット API キーは秘密として保持し、お使いのサーバのみに保存する必要があります。アカウントのシークレット API キーは、Stripe に対するあらゆる API リクエストを制限なく実行できます。
https://stripe.com/docs/keys

以上で、Stripe側の操作は終了です。

次に、アプリ側の操作に入ります。

### サーバ側

#### Stripe Nodeライブラリのインストール

下記コマンドで、必要なライブラリをインストールします。

```
npm install --save stripe
```

#### 支払用のセッションを作成する。

下記コードは、firebaseのfunctionで作成されています。
サーバ側で、セッション作成用のAPIを作成し、stripeのセッション情報を返却します。

>Checkout セッションは、ラインアイテム、注文金額と通貨、および受け付け可能な支払い方法など、Stripe のオンライン支払いページで顧客に表示される内容を制御します。レスポンスで Checkout セッションの ID を返し、クライアントでそのセッションを参照します。
https://stripe.com/docs/checkout/integration-builder

```javascript
const Stripe = require("stripe");

const stripe = new Stripe( STRIPE_SECRET_KEY, {
  apiVersion: '2020-08-27',
});

exports.createPaymentSession = functions.https.onCall(async(data, context) => {
  const session = await stripe.checkout.sessions.create({
    payment_method_types: ['card'],
    line_items: [
        {
        price_data: {
            currency: 'usd',
            product_data: {
            name: 'product',
            },
            unit_amount: 500,
        },
        quantity: 1,
        },
    ],
    mode: 'payment',
    success_url: 'http://localhost:3000/payment_success',
    cancel_url: 'http://localhost:3000/payment_cancel',
  })

  const res = session;
  console.log(res);
  return res;
});
```

各パラメータについて説明します。

```
payment_method_types: ['card'],
```

支払方法を指定しています。
>Checkout はカード以外にも複数の支払い方法に対応します。複数の支払い方法が渡された場合、Checkout は動的に支払い方法を並べ替え、顧客の場所や他の特性に基づいて最も適切な支払い方法を優先します。card が payment_method_types リストにある場合、該当するものがあれば、Checkout に Apple Pay や Google Pay も表示されます。
https://stripe.com/docs/checkout/integration-builder

card以外の支払方法は下記より確認できます。
https://stripe.com/docs/api/payment_methods/object

- acss_debit
- afterpay_clearpay
- alipay
- au_becs_debit
- bacs_debit
- bancontact
- card
- card_present
- eps
- fpx
- giropay
- grabpay
- ideal
- interac_present
- oxxo
- p24
- sepa_debit
- sofort

```
    line_items: [
        {
        price_data: {
            currency: 'usd',
            product_data: {
            name: 'product',
            },
            unit_amount: 500,
        },
        quantity: 1,
        },
    ],
```
商品情報を定義しています。
>価格や在庫状況など、商品在庫に関する機密情報は常にサーバー側に置き、顧客がクライアント側から操作できないようにします。商品情報は、price_data を使用してその場で定義できます。また、事前定義された価格を使用し、その ID を渡すこともできます。
https://stripe.com/docs/checkout/integration-builder

```
    mode: 'payment',
```
支払モードを指定しています。
>Checkout には、支払い、定期支払い、設定の 3 つのモードがあります。1 回限りの支払いには支払いモードを使用します。定期支払いモードと設定モードについてはドキュメントをご覧ください。
https://stripe.com/docs/checkout/integration-builder

```
    success_url: 'http://localhost:3000/payment_success',
    cancel_url: 'http://localhost:3000/payment_cancel',
```
リダイレクト先を指定しています。
>顧客が Checkout セッションを完了またはキャンセルしたときに、Stripe が顧客をリダイレクトする URL を指定します。成功とキャンセルの両方のステータスを同じ URL で処理できます。
https://stripe.com/docs/checkout/integration-builder

以上でサーバ側の操作は終了です。

### クライアント側(React)

次にクライアント側の操作に入ります。

#### Stripe Nodeライブラリのインストール

下記コマンドで、必要なライブラリをインストールします。

```
npm install @stripe/stripe-js
```

#### セッション作成APIを呼び出し、支払いページに遷移させる。

```typescript
import { loadStripe } from '@stripe/stripe-js';
import firebase from "firebase/app";
import "firebase/functions";

export async function showPayment(): Promise<void> {
    // セッション作成functionをインスタンス化
    const createPaymentSession = firebase.functions().httpsCallable('createPaymentSession');

    // 公開可能キーをもとに、stripeオブジェクトを作成
    const stripePromise = loadStripe(process.env.STRIPE_KEY);
    const stripe = await stripePromise;

    // セッション情報をもとに、支払いページに遷移
    createPaymentSession().then((result)=>{
        stripe.redirectToCheckout({
            sessionId: result.data.id,
        }).then((result)=>{
            console.log(result);
        });
    });
}
```

上記の関数を任意のボタン等で呼び出せば、下記のように支払いページを表示させることができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502798/118dfa00-c2ee-beb0-3ef1-f27d80e1f63d.png)


# おわりに
Stripeを本番利用するには、申請が必要です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502798/ea5aa7f9-f93f-d9ed-00ba-384bbec3117c.png)

ダッシュボードから申請できるので、実運用する際には申請を忘れずに行ってください。