【React×Firebase】StripeとCloudFunctionsで決済機能を作成してみる【Let's ハンズオン！】

ReactとFirebaseのCloudFunctionsを使ってStripeで決済機能を作れないか気になったので、調査してきたやで。

ほな、いくやで。

# 本日のゴール

こんな感じになれば今日はお勉強を終わってよし。

### メイン画面

![スクリーンショット 2022-03-20 16.30.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326114/3a6a3d0b-a5b5-ecbd-9283-d9c2d8e7f462.png)

stripeのボタンをクリックした後

### 決済画面
![スクリーンショット 2022-03-20 16.32.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326114/d4c8fa68-4c65-8d63-1cd0-74a68df3a4b5.png)


さぁ、かるぅく実装してやろうか。

# 環境構築
今回は以下の構成を作っていくやで

- client
　 Reactで画面側の処理を実装

- server
　 FirebaseのCloudFunctionsの処理を実装

以下みたいなディレクトリ構成を作ります。

![スクリーンショット 2022-03-20 16.27.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326114/a46fa785-d43c-a209-e95b-e5c78acb91ce.png)


## Client側(React)

まずはClient側の実装

```bash
create-react-app client --template typescript
```

Firebaseを使うので、以下をインストール
```bash
npm install firebase firebase-functions
```

後、Stripeも使うのでinstall 

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

まずはクライアントサイドからStripeを呼び出す関数を作成

```typescript:lib/firebase.ts
import { initializeApp } from 'firebase/app'
import { getFunctions, httpsCallable } from 'firebase/functions'
import { loadStripe } from "@stripe/stripe-js";

const firebaseConfig = {
  apiKey: process.env.REACT_APP_API_KEY,
  authDomain: process.env.REACT_APP_AUTH_DOMAIN,
  databaseURL: process.env.REACT_APP_DATABASE_URL,
  projectId: process.env.REACT_APP_PROJECT_ID,
  storageBucket: process.env.REACT_APP_STORAGE_BUCKET,
  messagingSenderId: process.env.REACT_APP_MESSAGING_SENDER_ID,
  appId: process.env.REACT_APP_APP_ID
};

const app = initializeApp(firebaseConfig)

export const getStripeAPI = async () => {
  try {
    const functions = getFunctions(app)
    const createPaymentSession = httpsCallable(functions, 'createPaymentSession');
     // 公開可能キーをもとに、stripeオブジェクトを作成
    const stripePromise = loadStripe({{Stripeの公開キー}});
    const stripe = await stripePromise;
    createPaymentSession({name: "hoge"})
      .then((result) => {
        const data:any = result.data;
        console.log("🚀 ~ file: firebase.ts ~ line 24 ~ .then ~ data", data)
        stripe!
        .redirectToCheckout({
          sessionId: data.id,
        })
        .then((result) => {
          console.log(result);
        });
      })
      .catch((error) => {
        const message = error.message;
        console.log("🚀 ~ file: firebase.ts ~ line 30 ~ getFirebaseAPI ~ message", message)
        console.log("🚀 ~ file: firebase.ts ~ line 30 ~ getFirebaseAPI ~ err", error)
      });
  } catch (error) {
    console.log("🚀 ~ file: firebase.ts ~ line 32 ~ getFirebaseAPI ~ error", error) 
  }
}

```

Firebaseとの接続に必要な各種キーを記載する.envファイルを作成
Firebaseのプロジェクトから取得しましょう。

```.env
REACT_APP_API_KEY="xxxxxxxxxxxxxxxxxx"
REACT_APP_AUTH_DOMAIN="xxxxxxxxxxxxxxxxxx"
REACT_APP_DATABASE_URL="xxxxxxxxxxxxxxxxxx"
REACT_APP_PROJECT_ID="xxxxxxxxxxxxxxxxxx"
REACT_APP_STORAGE_BUCKET="xxxxxxxxxxxxxxxxxx" 
REACT_APP_MESSAGING_SENDER_ID="xxxxxxxxxxxxxxxxxx"
REACT_APP_APP_ID="xxxxxxxxxxxxxxxxxx"

```

そして画面部分のApp.tsxも実装

```typescript:App.tsx
import './App.css';
import { getStripeAPI } from './lib/firebase';

function App() {
  const goStripe = async () => {
    await getStripeAPI();
  };

  return (
    <div className="App">
      <h1>Stripe 実装</h1>
      <button onClick={goStripe}>stripe </button>
    </div>
  );
}

export default App;
```

クライアントは以上です。


## Server側(CloudFunction)

clientと同階層にserverというディレクトリを作成してください。

こんな感じ。.gitignoreは無視しててね。

![スクリーンショット 2022-03-20 16.27.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326114/a46fa785-d43c-a209-e95b-e5c78acb91ce.png)

まずはなにがともあれnpm init。

```bash
npm init -y
```

CloudFunctionsを使うので、firebaseをインストール

```bash
npm install firebase-functions@latest firebase-admin@latest --save
npm install -g firebase-tools
```

CloudFunctionsの初期化を実行

```bash
firebase init functions
```

ここは時代の潮流に合わせてTypeScriptで実装しておきましょう。

そしてindex.tsに以下の関数を実装してください。

```typescript:src/index.ts
import * as functions from "firebase-functions";
const admin = require('firebase-admin');
admin.initializeApp();
const Stripe = require("stripe");

const stripe = new Stripe({{StripeのSecretキー}}, {
  apiVersion: "2020-08-27",
});

exports.createPaymentSession = functions.https.onCall(async (data, context) => {
  try {
  const session = await stripe.checkout.sessions.create({
    payment_method_types: ["card"],
    line_items: [
      {
        price:"{{商品のAPIキー}}",
        quantity: 1,
      },
    ],
    mode: "payment",
    //決済が終わった後にリダイレクトするURLを設定します
    success_url: `http://localhost:3000?payment_success`,
    cancel_url: `http://localhost:3000?payment_cancel`,
  });
    const res = session;
    functions.logger.log(res);
    return res
  } catch (error) {
    functions.logger.log("=========ERROR=========");
    functions.logger.log(error);
  }
});

```

これだけかければ実装は完了です！

みなさま本日もお疲れ様でした！

ゆうじろう

#最後に

これでこれからバシバシ商売ができるようになるやで

みんなが大金持ちになることを祈って終わりにします。


https://proaca.tech/

fin