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 .
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.
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>; }
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); };
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); };
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 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.
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; } }
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.
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.
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:
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.
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.
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:
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.
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); };
{ "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 } ] }
{ "amount": 2990 }
{ "amount": 2990 }
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); };
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:
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!