私のギャツビーTimshipsでストライプを実装する



導入
おいそこで👋🏽, この記事では統合するつもりですStripe 私の中にTimeship .
Timshipsはギャツビーで構築されます.用途Auth0 旅行する前にユーザを認証する.
ユーザーが場所、年に入力し、旅行データをベースに保存されてAirtable .
これらはすべて可能ですGatsby’s Serverless functions .

ストライプとは
Stripe 支払いを受け入れて、支払いを送ることができる支払い基盤です.
その設定の容易さは、それが開発者の間で好きになった要因の1つであって、どんな技術的な経験もない人々でさえあります.

目的
我々の仕事は、すべての旅行のために50ドルを請求することです.

ステップ1:セットアップのストライプアカウント
ストライプを使用するには、アカウントを作成する必要があります.アカウントはテストモードで起動します.

ステップ2:製品を作成する

当社のお客様のお支払いされる製品は、タイムアウトチケットです.したがって、我々は、価格、支払いのモードとその他の詳細とストライプに製品を追加します.


ステップ3:セットアップの歩哨
NPMや糸を使用してストライプをインストールします.
$ yarn add stripe
ダッシュボードの"APIキー"セクションからストライプ秘密キーを取得し、STRIPE_SECRET_KEY あなたの.環境変数開発ファイル.

The secret key should only be used server-side.



ステップ4 :ストライプチェックアウトセッションを作成する
チェックアウトセッションは、顧客が表示されるものです、彼らが彼らをリダイレクトするストライプチェックアウトページを通して彼らのチケットを支払うので.
以下は、顧客の詳細をポストリクエストを受け入れ、チェックアウトURLを返すServerless関数です.
// src/api/checkout-sessions.js

const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY)

export default async handler(req, res){
//POST request handler
  if(req.method === "POST"){
    const { email, year, location, cancelUrl, successUrl } = req.body;

        try{
            const session = await stripe.checkout.sessions.create({
                success_url: successUrl,
                cancel_url: cancelUrl,
                payment_method_types: ["card"],
                line_items: [{ price: "your pricing api id here", quantity: 1 }],
                mode: "payment",
                customer_email: email,
                metadata: {
                    email,
                    year,
                    location,
                },
            });
            return res.status(200).json({ url: session.url });
        } catch(error) {
            return res.status(error.status || 500).json({
            status: error.status || 500,
            message: error.message,
            });
        }
    }
    return res.status(405).json({ message: "Bad request" });
}
  • The success_url ページストライプは、支払いが成功するときにリダイレクトされます.ユーザーが「戻る」ボタンをクリックすると、ストライプはcancel_url
  • payment_method_types 顧客が私たちを支払うために使用する方法を指定します.
  • line_items , 顧客が購入したい項目のリスト.我々の場合では、それはちょうど1回の旅行チケットです.The price プロパティをpricing api id ステップ2で以前に作成した製品です.
  • mode つの列挙子:支払い、セットアップ、サブスクリプションがあります.現在はpayment それは一度の支払いだから.
  • customer_email , 顧客オブジェクトが作成されるとき、その値は使用されます.提供されないならば、顧客はチェックアウトページで彼らの電子メールを入力するよう頼まれます.
  • metadata 余分な詳細は、我々はトランザクションについて保存することがあります.私たちのケースでは、我々は電子メールを保存している
  • 一旦セッションがつくられるならば、ストライプは我々が我々のユーザーに返済するようにリダイレクトするURLを返します.ストライプチェックアウトページをテストするには、1つのテストカードストライプを使用できます4242 4242 4242 4242

    ステップ5:成功した支払いページ
    支払いが成功すると、ストライプはユーザーを成功URLにリダイレクトします.ストライプも追加されますsession_id クエリとして.
    成功メッセージを表示する前に、ParameterのセッションIDを使用してServiceレス関数へのGET要求を行い、支払いステータスを確認します.
    // src/api/checkout-sessions.js
    const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY)
    
    export default async handler(req, res){
    // POST request handler
    ...
    
    //GET REQUEST HANDLER
        if(req.method === "GET"){
            const session = await stripe.checkout.sessions.retrieve(req.query.sessionId);
            if (session.payment_status !== "paid") {
            throw new Error("You haven't paid for your ticket 👮🏽‍♀️🚨");
            }
        res.status(200).json({
            message: `You travelled to ${session.metadata.location} in the year ${session.metadata.year}`,
        });
    
        }
    }
    
    

    ステップ6 : Webhookエンドポイントを作成する
    これは最も重要な部分ですので、旅行するかどうか決定します.それをチケット検査官と考えてください👮🏽‍♂️.
    私は、ストライプがすぐに支払いにポストリクエストを作るエンドポイントを作成しました.サーバレス関数の実行
    つの関数は、私が個別にダイビングに呼び出されます.
    // src/api/webhook
    import axios from "axios";
    import createError from "http-errors";
    const stripe = require("stripe")(process.env.STRIPE_SECRET_KEY);
    
    export default async function handler(req, res) {
        try {
            if (req.method === "POST") {
                const { type, data } = req.body;
    
                // Check event type and payment status
                const session = await checkEventAndStatus(type, data);
    
                // Check if ticket is being re-used
                await checkTicketReuse(session.id);
    
                // Save travel details to Airtable
                await saveToAirtable(session);
    
                return res.status(201).json({
                    status: 201,
                    message: `success`,
                });
            }
            return res.status(401).json({ message: "Method not allowed" });
        } catch (error) {
            return res.status(error.status).json({ message: error.message });
        }
    }
    
    第一の機能checkEventAndStatus 受信するtype and data リクエストの本文からのプロパティ
    そして、それらを使用して、ストライプのウェブフックから来るイベントのタイプを特定します.
    また、支払いのステータス.この関数はチェックアウトセッションの詳細を持つオブジェクトを返します.
    // src/api/webhook
    
    async function checkEventAndStatus(type, data) {
        if (type !== "checkout.session.completed") {
            throw createError(401, "Event type not allowed");
        }
    
        const stripeSession = await stripe.checkout.sessions.retrieve(data.object.id);
        if (stripeSession.payment_status !== "paid") {
            throw createError(402, "You haven't paid for your ticket 👮🏽‍♀️🚨");
        }
    
        return stripeSession;
    }
    
    第二の機能checkTicketReuse 過去完了とクロスチェックするのに使用するセッションIDを受け入れます
    誰かがケースを再利用しようとする場合、私の航空可能な基地のセッションID.
    // src/api/webhook
    
    async function checkTicketReuse(sessionId) {
        const travellers = await axios.get(
            `https://api.airtable.com/v0/${process.env.AIRTABLE_BASE_KEY}/users`,
            {
                headers: {
                    Authorization: `Bearer ${process.env.AIRTABLE_API_KEY}`,
                },
            }
        );
    
        const records = travellers.data.records;
    
        const foundTicket = records.find(
            (passenger) => passenger.fields.ticket === sessionId
        );
    
        if (foundTicket) {
            throw createError(401, "This ticket has already been used");
        }
    }
    
    最後の関数saveToAirtable セッションオブジェクトを受け取り、格納したメタデータを取得します
    Step 4で早めて、旅行の詳細をAirtableに保存してください.
    // src/api/webhook
    
    async function saveToAirtable(session) {
        const currentTimestamp = Math.floor(Date.now() / 1000);
        await axios.post(
            `https://api.airtable.com/v0/${process.env.AIRTABLE_BASE_KEY}/users`,
            {
                records: [
                    {
                        fields: {
                            email: session.metadata.email,
                            year: parseInt(session.metadata.year),
                            location: session.metadata.location,
                            ticket: session.id,
                            timestamp: currentTimestamp,
                        },
                    },
                ],
            },
            {
                headers: {
                    Authorization: `Bearer ${process.env.AIRTABLE_API_KEY}`,
                },
            }
        );
    }
    

    ステップ7:ストライプのセットアップウェブフック
    前の手順を実行するには、我々は、ストライプダッシュボード上のwebhookを設定する必要があります.
    ヘッドオーバーwebhooks section と“エンドポイントを追加”をクリックします.Webhookをローカルでテストするために、ストライプCLIをインストールします.あなたはinstallation guide here .
    あなたのアプリケーションを実行しているポートにあなたのイベントを転送してください.Gatsbyでは、ポート8000を使用してエンドポイントパスを指定します.

    このセットを使用すると、アプリケーションを配備する前に、Webhookをローカルでテストすることができます.
    アプリケーションが配備されると、エンドポイントのURLをAdd an endpoint セクション.確認してくださいcheckout.session.completed イベント.

    そして今、宇宙と時間を旅することができます🚀.
    展開をチェックアウトしてくださいTimeshipcode on GitHub
    読書ありがとう❤️

    参考文献
  • Stripe Documentation