Heim > Web-Frontend > js-Tutorial > Hauptteil

Zahlungsgateways müssen im Allgemeinen nicht kompliziert sein

WBOY
Freigeben: 2024-08-16 06:17:02
Original
640 Leute haben es durchsucht

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

Integration von Zahlungsgateways mithilfe des Adaptermusters in Node.js und Fastify

Die Integration verschiedener Zahlungsgateways scheint eine herausfordernde Aufgabe zu sein, aber stellen Sie sich die Sicherheit vor, eine Lösung zu haben, die diesen Prozess einfach und effizient macht. Mit dem Design Pattern Adapter haben Sie die volle Kontrolle über Integrationen und erleichtern so die Wartung und Erweiterung Ihres Systems.

Stellen Sie sich jetzt vor, wie wertvoll es ist, eine Fähigkeit zu beherrschen, die Ihnen nicht nur Zeit spart, sondern auch die Qualität Ihres Codes erhöht. In diesem Artikel zeigen wir Ihnen, wie Sie bei der Integration eines Zahlungsgateways mit Node.js und Fastify, einer Technologie, die Entwickler auf der ganzen Welt überzeugt hat, von der Masse abheben können.

Wenn Sie Ihre Fähigkeiten auf die nächste Stufe bringen möchten, ist dieser Inhalt genau das Richtige für Sie. Lassen Sie uns gemeinsam die Erstellung von PIX-Gebühren mit der Woovi-API sowie andere Funktionen erkunden, die Sie vom Markt abheben werden.

Wir werden die Integration eines Zahlungsgateways mit Node.js und Fastify behandeln. Sie erfahren, wie Sie neben anderen Funktionen auch Gebühren über PIX mit der Woovi-API generieren.

Dieser Artikel ist Teil der CrazyStack Node.js-Klassen, in denen wir mit Node.js und Fastify eine REST-API von Grund auf entwickelt haben.Sie können den Beginn des Tutorials anhand der Videos hier und hier verfolgen .

Projektstruktur

Wir werden das Projekt modular strukturieren, wobei jedes Zahlungsgateway seine eigene Implementierung hat, aber alle einen gemeinsamen Vertrag haben. Wir werden TypeScript verwenden, um statische Typisierung und Codesicherheit zu gewährleisten.

Verzeichnisse und Dateien

  • src/
    • Verträge/
    • PaymentGateway.ts (Vertrag, der allen Gateways gemeinsam ist)
    • Adapter/
    • WooviAdapter.ts (Woovi-Gateway-Implementierung)
    • StripeAdapter.ts (Stripe-Gateway-Implementierung)
    • PagarmeAdapter.ts (Implementierung des Pagar.me-Gateways)
    • index.ts (Adapter-Einstiegspunkt)
    • config/
    • env.ts (Umgebungseinstellungen)

Payment Gateway-Vereinbarung

Der erste Schritt besteht darin, einen Vertrag zu definieren, den alle Zahlungsgateways umsetzen müssen. Dadurch wird sichergestellt, dass alle Gateways die gleichen Funktionen mit den gleichen Signaturen haben und somit die Konsistenz gewährleistet ist.

// 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>;
}
Nach dem Login kopieren

Adapter für Zahlungsgateways

Woovi-Zahlungsgateway

Die Adapterimplementierung für Woovi verwendet die Axios-Bibliothek, um HTTP-Aufrufe durchzuführen.

// 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);
};
Nach dem Login kopieren

Stripe-Zahlungsgateway

Für Stripe verwenden wir das offizielle 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);
};
Nach dem Login kopieren

Pagar.me-Zahlungsgateway

In der Dokumentation von Pagar.me wird detailliert beschrieben, wie Sie mithilfe ihrer API einen Client erstellen. Durch eine POST-Anfrage an den Endpunkt /customers ist es möglich, einen neuen Kunden auf der Plattform zu registrieren. Es ist wichtig zu beachten, dass das E-Mail-Feld eindeutig ist: Wenn bereits ein Kunde mit derselben E-Mail-Adresse vorhanden ist, werden die Daten aktualisiert, anstatt einen neuen Datensatz zu erstellen. Darüber hinaus können Kunden mit einem Reisepass nur mit gültigen internationalen Adressen Transaktionen tätigen.

Nun erkläre ich PagarmeAdapter anhand dieser Dokumentation:

PagarmeAdapter erklären

PagarmeAdapter ist eine Implementierung eines Adapters, der es Ihnen ermöglicht, mit der Pagar.me-API zu interagieren, um Kunden, Gebühren und Abonnements zu erstellen und zu verwalten. Es verwendet die Axios-Bibliothek, um HTTP-Aufrufe an die Pagar.me-API durchzuführen.

createCustomer-Funktion

Diese Funktion sendet eine POST-Anfrage an den Endpunkt Pagar.me /customers und übergibt die Kundendaten im Hauptteil der Anfrage. axios übernimmt die Authentifizierung mithilfe des API-Tokens (Bearer ${this.apiKey}) und gibt die erstellten oder aktualisierten Client-Daten zurück.

Anwendungsbeispiel:

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;
    }
}
Nach dem Login kopieren

Diese Funktion ist für die Registrierung oder Aktualisierung von Kunden auf Pagar.me direkt aus Ihrer Node.js-Anwendung mithilfe des Adaptermusters unerlässlich und gewährleistet die Flexibilität und Modularität des Systems.

Weitere Informationen zum Erstellen von Kunden auf Pagar.me finden Sie in der offiziellen Dokumentation hier.

Kunden gewinnen

In der Pagar.me-Dokumentation wird erläutert, wie Sie mithilfe der API Details zu einem bereits registrierten Kunden erhalten. Der spezifische Endpunkt hierfür ist GET https://api.pagar.me/core/v5/customers/{customer_id}, wobei {customer_id} die Kennung des Kunden ist, den Sie abfragen möchten.

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;
    }
}
Nach dem Login kopieren
Nach dem Login kopieren

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;
    }
}
Nach dem Login kopieren
Nach dem Login kopieren

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);
};
Nach dem Login kopieren

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
        }
    ]
}
Nach dem Login kopieren
  1. Captura de Transação Pré-autorizada
{
    "amount": 2990
}
Nach dem Login kopieren
Nach dem Login kopieren
  1. Reembolso de Transação
{
    "amount": 2990
}
Nach dem Login kopieren
Nach dem Login kopieren

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);
};
Nach dem Login kopieren

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-Kurs: crazystack.com.br
  • Repository auf GitHub: CrazyStackNodeJs

Bei diesem Kurs handelt es sich um eine praktische und intensive Schulung im Bootcamp-Format, die sich an Vollzeit- und Senior-Entwickler richtet, die die Art und Weise, wie sie Code schreiben, weiterentwickeln möchten. Sie lernen fortgeschrittene Konzepte wie Design Patterns, Clean Architecture, TDD und DDD, die in realen Projekten mit Node angewendet werden .js und Fastify.

Erfahren Sie mehr und melden Sie sich an!

Das obige ist der detaillierte Inhalt vonZahlungsgateways müssen im Allgemeinen nicht kompliziert sein. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Quelle:dev.to
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage