この記事はJAMstack Advent Calendar 2019 21日目の記事です。
JAMstackのアドベントカレンダーは7日目も参加しています。
qiita.com
こんにちはかみむらです。この記事ではReactでUIを作成して、Netlify Functionsを使ってStripeの決済処理を実装していきます。Stripeで決済処理するためにはサーバーを必要とするため、Netlify Functionsで作成したLambda関数を使って処理していきます。
JAMstackアーキテクチャの絶対条件として、サーバーに依存しない静的なサイトである必要があります。そのため、サーバーを伴う動的な処理(認証やコンテンツ管理、決済処理など)は、外部のAPIを使って実装していきます。今回はJAMstackなサイトに決済処理を実装する一例として、Stripeを使います。
JAMstackアーキテクチャの詳細については、こちらも一読してください。
今回書いたコードはこちらにあります。
目次
前提
Stripeのドキュメント
プロジェクトの作成
まずはcreate-react-appでプロジェクトを作成していきます。
$ npx create-react-app my-app
そして、アプリケーションが無事に起動するか試してみましょう。
$ yarn start
react-stripe-elementsの導入
Reactで簡単にStripeのUIを導入するためのコンポーネントライブラリを使います。こちらのライブラリです。
github.com
react-stripe-elementsのインストール
$ yarn add react-stripe-elements
そして、Stripe.jsを読み込みます。プロジェクトのpublicフォルダにあるindex.htmlファイルのHeadタグ内に下記のscriptを追加します。
public/index.html
<head> <title>React App</title> <script src="https://js.stripe.com/v3/"></script> </head>
チェックアウトフォームの作成
Netlify Functionsで作成したLambda関数に、クライアントからリクエストを送って決済処理を行います。Promiseベースのaxiosを使うと、シンプルにリクエストの処理を書くことができます。
axiosのインストール
$ yarn add axios
そして、こちらがチェックアウトフォームの内容です。
src/CheckoutForm.js
import React, {useState} from 'react'; import axios from 'axios'; import {CardElement, injectStripe} from 'react-stripe-elements'; const IS_PROD = process.env.NODE_ENV === 'production'; const ENDPOINT = IS_PROD ? 'netlify_url' : 'http://localhost:9000/charge'; const CheckoutForm = (props) => { const [amount, setAmount] = useState(2000); const handleSubmit = async (e) => { try { const {token} = await props.stripe.createToken({name: 'Name'}); const res = await axios.post( ENDPOINT, { amount: amount, body: token.id, }, { headers: { 'Content-Type': 'application/json', }, }, ); if (res) { console.log('ok'); } } catch (err) { console.log(err); } }; return ( <div> チェックアウト <CardElement /> <button onClick={handleSubmit}>チェックアウト</button> </div> ); }; export default injectStripe(CheckoutForm);
環境変数で本番環境とローカル環境のエンドポイントを分けています。netlify_urlには後ほどNetlify Functionsへデプロイしたときに発行されるエンドポイントを入れます。
const ENDPOINT = IS_PROD ? 'netlify_url' : 'http://localhost:9000/charge';
useStateでamountの合計値を設定します。今回は2000円決済します。
const [amount, setAmount] = useState(2000);
createToken()を呼び出して、カード情報と支払い情報をStripe上に登録します。ここで利用できるようになるinjectStripe()でnameキーの値として、'Name'文字列を渡しています。そして、そこで発行されるトークンをLambda関数に送ります。
const {token} = await props.stripe.createToken({name: 'Name'}); const res = await axios.post( ENDPOINT, { amount: amount, body: token.id, }, { headers: { 'Content-Type': 'application/json', }, }, );
こちらがApp.jsの内容です。StripeProviderコンポーネントは、Stripeを初期化し、APIキーを渡しています。your_apiではSripeのダッシュボードで確認したAPIキーを入れます。
src/App.js
import React from 'react'; import {Elements, StripeProvider} from 'react-stripe-elements'; import CheckoutForm from './CheckoutForm'; const App: React.FC = () => { return ( <div className="App"> <StripeProvider apiKey="your_api"> <Elements> <CheckoutForm /> </Elements> </StripeProvider> </div> ); } export default App;
Netlify Functionsで決済処理
次にNetlify FunctionsでLambda関数を作成していきます。新規のプロジェクトを作成しましょう。
$ mkdir my-functions && cd my-functions $ yarn init -y
そして、今回必要なパッケージをインストールします。
$ yarn add stripe netlify-lambda dotenv
こちらはLambda関数をデプロイするときの定義をします。netlify.tomlを追加します。
netlify.toml
[build] command = "yarn run build" functions = "build" Publish = "build"
Lambda関数を実行するscriptsも追加します。ここではyarn run devでlocalhost:9000で実行することができます。yarn run buildでビルドすることができます。
"scripts": { "dev": "netlify-lambda serve ./functions", "build": "netlify-lambda build ./functions" }
.envファイルを作成して、Stripeのシークレットキーを環境変数に入れます。このキーは外部に漏らしてはいけないので保護します。
.env
STRIPE_SECRET_KEY=""
こちらがLambda関数のロジックです。
functions/charge.js
require('dotenv').config(); const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY); const headers = { 'Access-Control-Allow-Origin': 'http://localhost:3000', 'Access-Control-Allow-Headers': 'Content-Type', }; exports.handler = async function(event) { if (event.httpMethod !== 'POST') { return { statusCode: 200, headers, body: 'Not POST Request', }; } const data = JSON.parse(event.body); if (event.httpMethod === 'POST') { try { await stripe.charges.create({ amount: parseInt(data.amount), currency: 'jpy', description: 'An example charge', source: data.body, }); return { statusCode: 200, headers, body: event.body, }; } catch (err) { console.log(err); } } };
ここではStripeライブラリを使って初期化します。先ほど指定した.envの変数を読み取ります。
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
そしてStripeクライアントライブラリを使用して、リクエストされたトークンと金額で決済処理を作成しています。ここではjpy(円)を指定しています。
await stripe.charges.create({ amount: parseInt(data.amount), currency: 'jpy', description: 'An example charge', source: data.body, });
ローカルで実行
ローカルで決済処理を確認するために、ReactアプリケーションとNetlify Functionsを2つ起動する必要があります。
Netlify Functions
$ yarn dev
Reactアプリケーション
$ yarn start
4242 4242 4242 4242でVISAカードでテストすることができます。必要項目を入力後、チェックアウトをクリックしてみましょう。
テストカードのドキュメントはこちらを読んでください。
stripe.com
そして、Stripeのダッシュボードを見てみましょう。設定した2000円が決済されてることが確認できます。
これで、Stripeの決済処理が完成しました。
Netlifyへデプロイ
今回作成したNetlify Functionsをデプロイしていきます。あらかじめ今回のプロジェクトをGitHubにプッシュしてください。
GitHubと連携後、ビルド設定をしていきます。
そして、Stripeのシークレットキーを環境変数にいれます。設定は以上です。デプロイしてみましょう。
これでデプロイが完了しました。
最後に
簡易的な決済処理を実装しました。今後、JAMstackアーキテクチャとStripeを用いた事例が増えてくればいいですね。