集成不同的支付网关似乎是一项具有挑战性的任务,但想象一下,如果有一个解决方案使此过程变得简单而高效,您会感到多么安心。通过设计模式适配器,您将完全控制集成,方便系统的维护和扩展。
现在,想象一下掌握一项技能的力量,它不仅可以节省您的时间,还可以提高代码的质量。在本文中,我们将向您展示如何在使用 Node.js 和 Fastify 集成支付网关时脱颖而出,Fastify 是一项赢得了世界各地开发者青睐的技术。
如果您致力于将自己的技能提升到一个新的水平,那么此内容适合您。让我们一起探索如何使用 Woovi API 创建 PIX 费用,以及使您在市场中脱颖而出的其他功能。
我们将介绍使用 Node.js 和 Fastify 的支付网关集成。除了其他功能之外,您还将了解如何使用 Woovi API 通过 PIX 生成费用。
本文是 CrazyStack Node.js 类的一部分,我们在其中使用 Node.js 和 Fastify 从头开始开发了 REST API。您可以通过此处和此处的视频跟随本教程的开头部分.
我们将以模块化的方式构建该项目,每个支付网关都有自己的实现,但每个人都将共享一个共同的合约。我们将使用 TypeScript 来确保静态类型和代码安全。
第一步是定义所有支付网关都必须实现的合约。这确保所有网关具有相同的功能和相同的签名,确保一致性。
// 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 的适配器实现使用 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 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 的文档详细介绍了如何使用其 API 创建客户端。通过向 /customers 端点发出 POST 请求,可以在平台上注册新客户。需要注意的是,电子邮件字段是唯一的:如果已存在具有相同电子邮件的客户,则数据将被更新,而不是创建新记录。此外,持有护照的客户只能使用有效的国际地址进行交易。
现在,根据这个文档解释PagarmeAdapter:
PagarmeAdapter 是适配器的实现,它允许您与 Pagar.me API 交互以创建和管理客户、费用和订阅。它使用 axios 库对 Pagar.me API 进行 HTTP 调用。
此函数向 Pagar.me /customers 端点发送 POST 请求,并在请求正文中传递客户数据。 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} 是您要查询的客户的标识符。
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:
本课程是训练营形式的实用强化培训,重点针对想要改进编写代码方式的全职和高级开发人员。您将学习诸如设计模式、简洁架构、TDD和DDD等高级概念,并通过Node应用于实际项目中.js 和 Fastify.
了解更多并注册!
以上是支付网关一般不必太复杂的详细内容。更多信息请关注PHP中文网其他相关文章!