ホームページ  >  記事  >  ウェブフロントエンド  >  一般的に、支払いゲートウェイは複雑である必要はありません

一般的に、支払いゲートウェイは複雑である必要はありません

WBOY
WBOYオリジナル
2024-08-16 06:17:02625ブラウズ

Gateway de pagamento de forma genérica não precisa ser complicado

Node.js と Fastify のアダプター パターンを使用したペイメント ゲートウェイの統合

さまざまな支払いゲートウェイを統合するのは難しい作業のように思えるかもしれませんが、このプロセスをシンプルかつ効率的にするソリューションがあることによる安心感を想像してみてください。デザイン パターン アダプター を使用すると、統合を完全に制御できるようになり、システムのメンテナンスと拡張が容易になります。

ここで、時間を節約するだけでなく、コードの品質も向上させるスキルを習得することの威力を視覚化してください。この記事では、Node.js と、世界中の開発者を魅了しているテクノロジーである Fastify を使用して決済ゲートウェイを統合する際に、どのように優れた点を実現できるかを明らかにします。

スキルを次のレベルに引き上げたいと考えている場合は、このコンテンツが最適です。 Woovi API を使用した PIX 料金の作成や、市場で目立つようにするその他の機能について一緒に調べてみましょう。

Node.jsFastify を使用した支払いゲートウェイの統合について説明します。他の機能に加えて、Woovi API を使用して PIX 経由で料金を生成する方法を学習します。

この記事は CrazyStack Node.js クラスの一部であり、Node.js と Fastify を使用して REST API を最初から開発しました。 こことここのビデオでチュートリアルの始まりを追うことができます。 .

プロジェクトの構造

私たちはモジュール方式でプロジェクトを構造化します。各支払いゲートウェイは独自の実装を持ちますが、全員が共通の契約を共有します。 TypeScript を使用して、静的型付けとコードのセキュリティを確保します。

ディレクトリとファイル

  • ソース/
    • 契約/
    • PaymentGateway.ts (全ゲートウェイ共通契約)
    • アダプター/
    • WooviAdapter.ts (Woovi ゲートウェイ実装)
    • StripeAdapter.ts (ストライプゲートウェイ実装)
    • PagarmeAdapter.ts (Pagar.me ゲートウェイの実装)
    • Index.ts (アダプターのエントリーポイント)
    • config/
    • env.ts (環境設定)

ペイメントゲートウェイ契約

最初のステップは、すべての支払いゲートウェイが実装する必要がある契約を定義することです。これにより、すべてのゲートウェイが同じ署名を持つ同じ機能を持ち、一貫性が保証されます。

// src/contracts/PaymentGateway.ts
export abstract class PaymentGateway {
  abstract createCharge(data: any): Promise<any>;
  abstract deleteCharge(id: string): Promise<any>;
  abstract getCharge(id: string): Promise<any>;
  abstract createSubscription(data: any): Promise<any>;
  abstract getSubscription(id: string): Promise<any>;
  abstract createCustomer(data: any): Promise<any>;
  abstract getCustomer(id: string): Promise<any>;
  abstract getChargeByCustomer(data: any): Promise<any>;
}

ペイメントゲートウェイ用アダプター

Woovi ペイメントゲートウェイ

Woovi のアダプター実装は、axios ライブラリを使用して HTTP 呼び出しを行います。

// src/adapters/WooviAdapter.ts
import axios from "axios";
import { PaymentGateway } from "../contracts";
import { env } from "../config";

export class WooviPaymentGateway extends PaymentGateway {
  private apiKey: string;

  constructor(paymentKey: string) {
    super();
    this.apiKey = paymentKey;
  }

  async deleteCharge(id: string): Promise<any> {
    try {
      const response = await axios.delete(
        `https://api.openpix.com.br/api/v1/charge/${id}`,
        {
          headers: { Authorization: this.apiKey },
        }
      );
      return response?.data;
    } catch (e: any) {
      return e?.response?.data;
    }
  }

  async getCharge(id: string): Promise<any> {
    try {
      const response = await axios.get(
        `https://api.openpix.com.br/api/v1/charge/${id}`,
        {
          headers: { Authorization: this.apiKey, "content-type": "application/json" },
        }
      );
      return response?.data;
    } catch (e: any) {
      return e?.response?.data;
    }
  }

  async createCharge(data: any): Promise<any> {
    const { correlationID, value, comment } = data;
    try {
      const { data } = await axios.post(
        "https://api.openpix.com.br/api/v1/charge?return_existing=true",
        { correlationID, value, comment },
        {
          headers: { Authorization: this.apiKey, "content-type": "application/json" },
        }
      );
      return data;
    } catch (e: any) {
      return e?.response?.data;
    }
  }

  async createSubscription(body: any): Promise<any> {
    try {
      const { data } = await axios.post(
        "https://api.openpix.com.br/api/v1/subscriptions",
        body,
        {
          headers: { Authorization: this.apiKey, "content-type": "application/json" },
        }
      );
      return data;
    } catch (e: any) {
      return e?.response?.data;
    }
  }

  async getSubscription(id: string): Promise<any> {
    try {
      const response = await axios.get(
        `https://api.openpix.com.br/api/v1/subscriptions/${id}`,
        {
          headers: { Authorization: this.apiKey, "content-type": "application/json" },
        }
      );
      return response?.data;
    } catch (e: any) {
      return e?.response?.data;
    }
  }

  async createCustomer(body: any): Promise<any> {
    try {
      const { data } = await axios.post(
        "https://api.openpix.com.br/api/v1/customer",
        body,
        {
          headers: { Authorization: this.apiKey, "content-type": "application/json" },
        }
      );
      return data;
    } catch (e: any) {
      return e?.response?.data;
    }
  }

  async getCustomer(id: string): Promise<any> {
    try {
      const response = await axios.get(
        `https://api.openpix.com.br/api/v1/customer/${id}`,
        {
          headers: { Authorization: this.apiKey, "content-type": "application/json" },
        }
      );
      return response?.data;
    } catch (e: any) {
      return e?.response?.data;
    }
  }

  async getChargeByCustomer(correlationID: string): Promise<any> {
    try {
      const response = await axios.get(
        `https://api.openpix.com.br/api/v1/charge?customer=${correlationID}&status=ACTIVE`,
        {
          headers: { Authorization: this.apiKey, "content-type": "application/json" },
        }
      );
      return response?.data;
    } catch (e: any) {
      return e?.response?.data;
    }
  }
}

export const makeWooviAdapter = () => {
  return new WooviPaymentGateway(env.wooviKey);
};

Stripe ペイメント ゲートウェイ

Stripe の場合、公式の Stripe SDK を使用します。

// src/adapters/StripeAdapter.ts
import { PaymentGateway } from "../contracts";
import { env } from "../config";
import Stripe from "stripe";

export class StripePaymentGateway extends PaymentGateway {
  private stripe: Stripe;

  constructor(paymentKey: string) {
    super();
    this.stripe = new Stripe(paymentKey, {
      apiVersion: "2023-10-16",
      typescript: true,
    });
  }

  async createPrice(amount: number): Promise<any> {
    try {
      const price = await this.stripe.prices.create({
        currency: "brl",
        unit_amount: amount,
        recurring: { interval: "month" },
        product_data: { name: "Gold Plan" },
      });
      return { price };
    } catch (e: any) {
      return e?.response?.data;
    }
  }

  async createSubscription(data: any): Promise<any> {
    try {
      const subscription = await this.stripe.subscriptions.create({
        customer: data?.customer?.id ?? data?.customer?.correlationID,
        items: [{ price: data?.priceId }],
      });
      return { subscription };
    } catch (e: any) {
      return e?.response?.data;
    }
  }

  async getSubscription(id: string): Promise<any> {
    try {
      const subscription = await this.stripe.subscriptions.retrieve(id);
      return { subscription };
    } catch (e: any) {
      return e?.response?.data;
    }
  }

  async deleteCharge(id: string): Promise<any> {
    try {
      const charge = await this.stripe.paymentIntents.update(id, {
        metadata: { status: "canceled" },
      });
      return { charge, status: "OK" };
    } catch (e: any) {
      return e?.response?.data;
    }
  }

  async getCharge(id: string): Promise<any> {
    try {
      const charge = await this.stripe.paymentIntents.retrieve(id);
      return { charge };
    } catch (e: any) {
      return e?.response?.data;
    }
  }

  async createCharge(data: any): Promise<any> {
    try {
      const charge = await this.stripe.paymentIntents.create({
        amount: Number(data?.value),
        currency: "brl",
        metadata: { metadata: JSON.stringify(data) },
        automatic_payment_methods: { enabled: true },
      });
      return { charge };
    } catch (e: any) {
      return e?.response?.data;
    }
  }

  async createCustomer(data: any): Promise<any> {
    const { email, description } = data;
    try {
      const customer: Stripe.Customer = await this.stripe.customers.create({
        description,
        email

,
      });
      return { customer };
    } catch (e: any) {
      return e?.response?.data;
    }
  }

  async getCustomer(id: string): Promise<any> {
    try {
      const customer = await this.stripe.customers.retrieve(id);
      return { customer };
    } catch (e: any) {
      return e?.response?.data;
    }
  }
}

export const makeStripeAdapter = () => {
  return new StripePaymentGateway(env.stripeKeySecret);
};

Pagar.me ペイメントゲートウェイ

Pagar.me のドキュメントには、API を使用してクライアントを作成する方法が詳しく記載されています。 /customers エンドポイントへの POST リクエストを通じて、プラットフォームに新しい顧客を登録できます。 電子メール フィールドは一意である ことに注意することが重要です。同じ電子メールを持つ顧客がすでに存在する場合、新しいレコードは作成されずにデータが更新されます。さらに、パスポートをお持ちのお客様は、有効な国際住所でのみ取引できます。

次に、このドキュメントに基づいて PagarmeAdapter について説明します。

PagarmeAdapter の説明

PagarmeAdapter は、Pagar.me API と対話して顧客、請求、サブスクリプションを作成および管理できるようにするアダプターの実装です。 axios ライブラリを使用して、Pagar.me API への HTTP 呼び出しを行います。

createCustomer関数

この関数は POST リクエストを Pagar.me /customers エンドポイントに送信し、リクエストの本文で顧客データを渡します。 axios は API トークン (Bearer ${this.apiKey}) を使用して認証を処理し、作成または更新されたクライアント データを返します。

使用例:

async createCustomer(data: any): Promise<any> {
    try {
        const response = await axios.post(
            "https://api.pagar.me/1/customers",
            data,
            {
                headers: { Authorization: `Bearer ${this.apiKey}` },
            }
        );
        return response?.data;
    } catch (e: any) {
        return e?.response?.data;
    }
}

この機能は、アダプター パターンを使用して Node.js アプリケーションから直接 Pagar.me に顧客を登録または更新する場合に不可欠であり、システムの柔軟性とモジュール性を確保します。

Pagar.me での顧客の作成の詳細については、こちらの公式ドキュメントを参照してください。

顧客を獲得する

Pagar.me のドキュメントでは、API を使用して登録済みの顧客の詳細を取得する方法について説明しています。このための具体的なエンドポイントは GET https://api.pagar.me/core/v5/customers/{customer_id} です。ここで、{customer_id} はクエリする顧客の識別子です。

Explicação do PagarmeAdapter - Função getCustomer

A função getCustomer dentro do PagarmeAdapter realiza exatamente essa operação. Ela faz uma requisição GET para o endpoint da Pagar.me, utilizando o customer_id fornecido. Aqui está como funciona:

  1. Autenticação: A função utiliza o token de API (Bearer ${this.apiKey}) para autenticar a requisição.
  2. Requisição: Faz a chamada GET para o endpoint da Pagar.me, buscando os detalhes do cliente correspondente ao customer_id.
  3. Resposta: Retorna os dados do cliente se a requisição for bem-sucedida ou a resposta de erro em caso de falha.

Exemplo de uso:

async getCustomer(id: string): Promise<any> {
    try {
        const response = await axios.get(
            `https://api.pagar.me/1/customers/${id}`,
            {
                headers: { Authorization: `Bearer ${this.apiKey}` },
            }
        );
        return response?.data;
    } catch (e: any) {
        return e?.response?.data;
    }
}

Essa função permite que você obtenha informações detalhadas sobre um cliente específico, diretamente da API da Pagar.me, integrando facilmente essa funcionalidade ao seu sistema Node.js. Para mais detalhes, você pode consultar a documentação oficial aqui.

Criando transactions

A documentação da Pagar.me explica como obter detalhes de um cliente já cadastrado usando a API. O endpoint específico para isso é o GET https://api.pagar.me/core/v5/customers/{customer_id}, onde {customer_id} é o identificador do cliente que você deseja consultar.

Explicação do PagarmeAdapter - Função getCustomer

A função getCustomer dentro do PagarmeAdapter realiza exatamente essa operação. Ela faz uma requisição GET para o endpoint da Pagar.me, utilizando o customer_id fornecido. Aqui está como funciona:

  1. Autenticação: A função utiliza o token de API (Bearer ${this.apiKey}) para autenticar a requisição.
  2. Requisição: Faz a chamada GET para o endpoint da Pagar.me, buscando os detalhes do cliente correspondente ao customer_id.
  3. Resposta: Retorna os dados do cliente se a requisição for bem-sucedida ou a resposta de erro em caso de falha.

Exemplo de uso:

async getCustomer(id: string): Promise<any> {
    try {
        const response = await axios.get(
            `https://api.pagar.me/1/customers/${id}`,
            {
                headers: { Authorization: `Bearer ${this.apiKey}` },
            }
        );
        return response?.data;
    } catch (e: any) {
        return e?.response?.data;
    }
}

Essa função permite que você obtenha informações detalhadas sobre um cliente específico, diretamente da API da Pagar.me, integrando facilmente essa funcionalidade ao seu sistema Node.js. Para mais detalhes, você pode consultar a documentação oficial aqui.
Vamos expandir o PagarmeAdapter para incluir métodos específicos para lidar com transações de cartão de crédito, seguindo a documentação da API Pagar.me. Também fornecerei exemplos de payloads de teste que você pode usar para verificar cada método.

Métodos do PagarmeAdapter para Cartão de Crédito

Aqui está a implementação dos métodos do PagarmeAdapter:

import axios from "axios";
import { PaymentGateway } from "../contracts";
import { env } from "../config";

export class PagarmePaymentGateway extends PaymentGateway {
  private apiKey: string;

  constructor(paymentKey: string) {
    super();
    this.apiKey = paymentKey;
  }

  async createCharge(data: any): Promise<any> {
    try {
      const response = await axios.post(
        "https://api.pagar.me/1/transactions",
        data,
        {
          headers: { Authorization: `Bearer ${this.apiKey}` },
        }
      );
      return response?.data;
    } catch (e: any) {
      return e?.response?.data;
    }
  }

  async deleteCharge(id: string): Promise<any> {
    try {
      const response = await axios.delete(
        `https://api.pagar.me/1/transactions/${id}`,
        {
          headers: { Authorization: `Bearer ${this.apiKey}` },
        }
      );
      return response?.data;
    } catch (e: any) {
      return e?.response?.data;
    }
  }

  async getCharge(id: string): Promise<any> {
    try {
      const response = await axios.get(
        `https://api.pagar.me/1/transactions/${id}`,
        {
          headers: { Authorization: `Bearer ${this.apiKey}` },
        }
      );
      return response?.data;
    } catch (e: any) {
      return e?.response?.data;
    }
  }

  async captureCharge(id: string, amount: number): Promise<any> {
    try {
      const response = await axios.post(
        `https://api.pagar.me/1/transactions/${id}/capture`,
        { amount },
        {
          headers: { Authorization: `Bearer ${this.apiKey}` },
        }
      );
      return response?.data;
    } catch (e: any) {
      return e?.response?.data;
    }
  }

  async refundCharge(id: string, amount: number): Promise<any> {
    try {
      const response = await axios.post(
        `https://api.pagar.me/1/transactions/${id}/refund`,
        { amount },
        {
          headers: { Authorization: `Bearer ${this.apiKey}` },
        }
      );
      return response?.data;
    } catch (e: any) {
      return e?.response?.data;
    }
  }
}

export const makePagarmeAdapter = () => {
  return new PagarmePaymentGateway(env.pagarmeKey);
};

Exemplos de Payloads de Teste

  1. Criação de Transação com Cartão de Crédito (Auth & Capture)
{
    "amount": 2990,
    "payment_method": "credit_card",
    "card_number": "4000000000000010",
    "card_cvv": "123",
    "card_expiration_date": "1225",
    "card_holder_name": "Tony Stark",
    "customer": {
        "external_id": "#3311",
        "name": "Tony Stark",
        "type": "individual",
        "country": "br",
        "email": "tonystark@avengers.com",
        "documents": [
            {
                "type": "cpf",
                "number": "12345678909"
            }
        ],
        "phone_numbers": ["+5511999998888"],
        "birthday": "1967-03-01"
    },
    "billing": {
        "name": "Tony Stark",
        "address": {
            "country": "br",
            "state": "sp",
            "city": "Sao Paulo",
            "neighborhood": "Bela Vista",
            "street": "Avenida Paulista",
            "street_number": "1000",
            "zipcode": "01310000"
        }
    },
    "items": [
        {
            "id": "r123",
            "title": "Chaveiro do Tesseract",
            "unit_price": 2990,
            "quantity": 1,
            "tangible": true
        }
    ]
}
  1. Captura de Transação Pré-autorizada
{
    "amount": 2990
}
  1. Reembolso de Transação
{
    "amount": 2990
}

Explicação

  • createCharge: Cria uma nova transação de cartão de crédito.
  • deleteCharge: Cancela uma transação existente.
  • getCharge: Obtém os detalhes de uma transação específica.
  • captureCharge: Captura uma transação que foi previamente autorizada.
  • refundCharge: Realiza o estorno de uma transação.

Esses métodos cobrem as principais operações que você pode realizar com transações de cartão de crédito utilizando a API Pagar.me. Os payloads fornecidos são exemplos básicos que você pode utilizar para testar essas funcionalidades.

Código completo

// src/adapters/PagarmeAdapter.ts
import axios from "axios";
import { PaymentGateway } from "../contracts";
import { env } from "../config";

export class PagarmePaymentGateway extends PaymentGateway {
  private apiKey: string;

  constructor(paymentKey: string) {
    super();
    this.apiKey = paymentKey;
  }

  async createCharge(data: any): Promise<any> {
    try {
      const response = await axios.post(
        "https://api.pagar.me/1/transactions",
        data,
        {
          headers: { Authorization: `Bearer ${this.apiKey}` },
        }
      );
      return response?.data;
    } catch (e: any) {
      return e?.response?.data;
    }
  }

  async deleteCharge(id: string): Promise<any> {
    try {
      const response = await axios.delete(
        `https://api.pagar.me/1/transactions/${id}`,
        {
          headers: { Authorization: `Bearer ${this.apiKey}` },
        }
      );
      return response?.data;
    } catch (e: any) {
      return e?.response?.data;
    }
  }

  async getCharge(id: string): Promise<any> {
    try {
      const response = await axios.get(
        `https://api.pagar.me/1/transactions/${id}`,
        {
          headers: { Authorization: `Bearer ${this.apiKey}` },
        }
      );
      return response?.data;
    } catch (e: any) {
      return e?.response?.data;
    }
  }

  async createSubscription(data: any): Promise<any> {
    try {
      const response = await axios.post(
        "https://api.pagar.me/1/subscriptions",
        data,
        {
          headers: { Authorization: `Bearer ${this.apiKey}` },
        }
      );
      return response?.data;
    } catch (e: any) {
      return e?.response?.data;
    }
  }

  async getSubscription(id: string): Promise<any> {
    try {
      const response = await axios.get(
        `https://api.pagar.me/1/subscriptions/${id}`,
        {
          headers: { Authorization: `Bearer ${this.apiKey}` },
        }
      );
      return response?.data;
    } catch (e: any) {
      return e?.response?.data;
    }
  }

  async createCustomer(data: any): Promise<any> {
    try {
      const response = await axios.post(
        "https://api.pagar.me/1/customers",
        data,
        {
          headers: { Authorization: `Bearer ${this.apiKey}` },
        }
      );
      return response?.data;
    } catch (e: any) {
      return e?.response?.data;
    }
  }

  async getCustomer(id: string): Promise<any> {
    try {
      const response = await axios.get(
        `https://api.pagar.me/1/customers/${id}`,
        {
          headers: { Authorization: `Bearer ${this.apiKey}` },
        }
      );
      return response?.data;
    } catch (e: any) {
      return e?.response?.data;
    }
  }

  async getChargeByCustomer(correlationID: string): Promise<any> {
    try {
      const response = await axios.get(
        `https://api.pagar.me/1/transactions?customer=${correlationID}`,
        {
          headers: { Authorization: `Bearer ${this.apiKey}` },
        }
      );
      return response?.data;
    } catch (e: any) {
      return e?.response?.data;
    }
  }
}

export const makePagarmeAdapter = () => {
  return new PagarmePaymentGateway(env.pagarmeKey);
};

Conclusão

Implementar gateways de pagamento utilizando o padrão Adapter em TypeScript facilita a integração e a manutenção do código. Ao seguir essa abordagem, você garante flexibilidade e modularidade no seu sistema, podendo adicionar ou substituir gateways com facilidade.

Para uma compreensão mais detalhada e prática sobre como implementar um gateway de pagamento com Node.js e Fastify, assista ao nosso vídeo tutorial completo na Aula 99 do CrazyStack Node.js. Não perca essa oportunidade de aprofundar seu conhecimento e dominar as melhores práticas de desenvolvimento de sistemas de pagamento.

? Links Importantes:

  • CrazyStack TypeScript コース:crazystack.com.br
  • GitHub 上のリポジトリ: CrazyStackNodeJs

このコースは、コードの書き方を進化させたいフルタイム開発者および上級開発者に焦点を当てた、ブートキャンプ形式の実践的で集中的なトレーニングです。 デザインパターンクリーンアーキテクチャTDDDDDなどの高度な概念を学び、ノードを使用して実際のプロジェクトに適用されます。 .js および Fastify.

詳細を確認してサインアップしてください!

以上が一般的に、支払いゲートウェイは複雑である必要はありませんの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。