third-party-integration

安装量: 116
排名: #7390

安装

npx skills add https://github.com/aj-geddes/useful-ai-prompts --skill third-party-integration

Third-Party Integration Overview

Build robust integrations with external services using standardized patterns for API calls, error handling, authentication, and data transformation.

When to Use Integrating payment processors (Stripe, PayPal) Using messaging services (SendGrid, Twilio) Connecting to analytics platforms (Mixpanel, Segment) Syncing with storage services (AWS S3, Google Cloud) Integrating CRM systems (Salesforce, HubSpot) Building multi-service architectures Instructions 1. Third-Party Client Wrapper const axios = require('axios');

class ThirdPartyClient { constructor(config) { this.apiKey = config.apiKey; this.baseUrl = config.baseUrl; this.timeout = config.timeout || 30000; this.retryAttempts = config.retryAttempts || 3; this.retryDelay = config.retryDelay || 1000; this.client = axios.create({ baseURL: this.baseUrl, timeout: this.timeout, headers: { 'Authorization': Bearer ${this.apiKey}, 'Content-Type': 'application/json' } }); }

async request(method, endpoint, data = null, options = {}) { let lastError;

for (let attempt = 0; attempt < this.retryAttempts; attempt++) {
  try {
    const response = await this.client({
      method,
      url: endpoint,
      data,
      timeout: this.timeout,
      ...options
    });

    return {
      success: true,
      data: response.data,
      statusCode: response.status,
      headers: response.headers
    };
  } catch (error) {
    lastError = error;

    // Check if error is retryable
    if (!this.isRetryable(error) || attempt === this.retryAttempts - 1) {
      break;
    }

    // Exponential backoff
    const delay = this.retryDelay * Math.pow(2, attempt);
    await this.sleep(delay);
  }
}

return this.handleError(lastError);

}

isRetryable(error) { if (!error.response) return true; // Network error

const status = error.response.status;
// Retry on 5xx and specific 4xx errors
return status >= 500 || [408, 429].includes(status);

}

handleError(error) { if (error.response) { return { success: false, error: { message: error.response.data?.message || error.message, code: error.response.data?.code || error.response.status, status: error.response.status, data: error.response.data } }; }

return {
  success: false,
  error: {
    message: error.message,
    code: 'NETWORK_ERROR'
  }
};

}

sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); }

async get(endpoint) { return this.request('GET', endpoint); }

async post(endpoint, data) { return this.request('POST', endpoint, data); }

async put(endpoint, data) { return this.request('PUT', endpoint, data); }

async delete(endpoint) { return this.request('DELETE', endpoint); } }

// Usage const stripeClient = new ThirdPartyClient({ apiKey: process.env.STRIPE_API_KEY, baseUrl: 'https://api.stripe.com/v1', timeout: 30000, retryAttempts: 3 });

const result = await stripeClient.post('/charges', { amount: 10000, currency: 'usd', source: 'tok_visa' });

  1. Payment Processor Integration (Stripe) const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);

class PaymentService { async createCharge(userId, amount, paymentMethodId) { try { const customer = await this.getOrCreateCustomer(userId);

  const charge = await stripe.charges.create({
    amount: Math.round(amount * 100), // cents
    currency: 'usd',
    customer: customer.id,
    payment_method: paymentMethodId,
    confirm: true
  });

  // Log transaction
  await Transaction.create({
    userId,
    chargeId: charge.id,
    amount,
    status: charge.status,
    createdAt: new Date(charge.created * 1000)
  });

  return {
    success: true,
    chargeId: charge.id,
    status: charge.status
  };
} catch (error) {
  console.error('Charge error:', error.message);

  if (error.code === 'card_declined') {
    return { success: false, error: 'Card declined' };
  }

  throw error;
}

}

async refund(chargeId, amount = null) { try { const refund = await stripe.refunds.create({ charge: chargeId, amount: amount ? Math.round(amount * 100) : undefined });

  await Transaction.updateOne(
    { chargeId },
    { refundId: refund.id, status: 'refunded' }
  );

  return { success: true, refundId: refund.id };
} catch (error) {
  console.error('Refund error:', error.message);
  throw error;
}

}

async getOrCreateCustomer(userId) { let customer = await Customer.findOne({ userId });

if (!customer) {
  const stripeCustomer = await stripe.customers.create({
    metadata: { userId }
  });

  customer = await Customer.create({
    userId,
    stripeId: stripeCustomer.id
  });
}

return customer;

}

async handleWebhook(event) { switch (event.type) { case 'charge.succeeded': await this.handleChargeSucceeded(event.data.object); break; case 'charge.failed': await this.handleChargeFailed(event.data.object); break; case 'refund.created': await this.handleRefund(event.data.object); break; } } }

// Webhook endpoint app.post('/webhooks/stripe', express.raw({type: 'application/json'}), async (req, res) => { const sig = req.headers['stripe-signature'];

try { const event = stripe.webhooks.constructEvent( req.body, sig, process.env.STRIPE_WEBHOOK_SECRET );

await paymentService.handleWebhook(event);
res.json({ received: true });

} catch (error) { res.status(400).json({ error: error.message }); } });

  1. Email Service Integration (SendGrid) const sgMail = require('@sendgrid/mail'); sgMail.setApiKey(process.env.SENDGRID_API_KEY);

class EmailService { async sendEmail(to, templateId, templateData = {}) { try { const message = { to, from: process.env.FROM_EMAIL, templateId, dynamicTemplateData: { ...templateData, timestamp: new Date().toISOString() }, trackingSettings: { clickTracking: { enabled: true }, openTracking: { enabled: true } } };

  const response = await sgMail.send(message);

  // Log email
  await EmailLog.create({
    to,
    templateId,
    messageId: response[0].headers['x-message-id'],
    status: 'sent',
    sentAt: new Date()
  });

  return { success: true, messageId: response[0].headers['x-message-id'] };
} catch (error) {
  console.error('Email error:', error.message);

  await EmailLog.create({
    to,
    templateId,
    error: error.message,
    status: 'failed'
  });

  throw error;
}

}

async sendBulk(recipients, templateId, templateData) { const promises = recipients.map(recipient => this.sendEmail(recipient, templateId, templateData).catch(err => ({ recipient, error: err.message })) );

return Promise.allSettled(promises);

}

async handleWebhook(event) { const { messageId, event: eventType } = event;

await EmailLog.updateOne(
  { messageId },
  { status: eventType, updatedAt: new Date() }
);

} }

// Usage const emailService = new EmailService();

app.post('/api/send-welcome-email', async (req, res) => { const { email, firstName } = req.body;

const result = await emailService.sendEmail(email, 'd-welcome-template-id', { firstName });

res.json(result); });

  1. Python Third-Party Integration import requests import time from typing import Optional, Dict, Any from datetime import datetime import logging

logger = logging.getLogger(name)

class APIClient: def init(self, api_key: str, base_url: str, timeout: int = 30): self.api_key = api_key self.base_url = base_url self.timeout = timeout self.session = requests.Session() self.session.headers.update({ 'Authorization': f'Bearer {api_key}', 'Content-Type': 'application/json' })

def request(
    self,
    method: str,
    endpoint: str,
    data: Optional[Dict] = None,
    max_retries: int = 3
) -> Dict[str, Any]:
    url = f"{self.base_url}/{endpoint}"
    attempt = 0

    while attempt < max_retries:
        try:
            response = self.session.request(
                method,
                url,
                json=data,
                timeout=self.timeout
            )

            if response.status_code >= 200 and response.status_code < 300:
                return {
                    'success': True,
                    'data': response.json(),
                    'status': response.status_code
                }

            if response.status_code >= 500 or response.status_code == 429:
                raise requests.RequestException(f"HTTP {response.status_code}")

            return {
                'success': False,
                'error': response.json().get('message', 'Error'),
                'status': response.status_code
            }

        except requests.RequestException as e:
            attempt += 1
            if attempt >= max_retries:
                logger.error(f"API request failed: {e}")
                return {
                    'success': False,
                    'error': str(e),
                    'status': None
                }

            wait_time = 2 ** attempt
            time.sleep(wait_time)

    return {'success': False, 'error': 'Max retries exceeded'}

def get(self, endpoint: str) -> Dict[str, Any]:
    return self.request('GET', endpoint)

def post(self, endpoint: str, data: Dict) -> Dict[str, Any]:
    return self.request('POST', endpoint, data)

def put(self, endpoint: str, data: Dict) -> Dict[str, Any]:
    return self.request('PUT', endpoint, data)

def delete(self, endpoint: str) -> Dict[str, Any]:
    return self.request('DELETE', endpoint)

Payment processor example

class PaymentGateway(APIClient): def create_payment(self, amount: float, currency: str, customer_id: str): return self.post('charges', { 'amount': int(amount * 100), 'currency': currency, 'customer': customer_id })

def refund(self, charge_id: str, amount: Optional[float] = None):
    return self.post(f'charges/{charge_id}/refund', {
        'amount': int(amount * 100) if amount else None
    })
  1. Data Transformation class DataMapper { static stripeChargeToTransaction(charge) { return { id: charge.id, amount: charge.amount / 100, currency: charge.currency, status: charge.status, customerId: charge.customer, createdAt: new Date(charge.created * 1000), metadata: charge.metadata }; }

static sendgridEmailToLog(event) { return { messageId: event.sg_message_id, email: event.email, eventType: event.event, timestamp: new Date(event.timestamp * 1000), metadata: event }; }

static awsS3FileToRecord(s3Object) { return { key: s3Object.Key, size: s3Object.Size, lastModified: s3Object.LastModified, etag: s3Object.ETag, bucket: s3Object.Bucket }; } }

Best Practices ✅ DO Implement retry logic with exponential backoff Validate webhook signatures Log all API interactions Use environment variables for secrets Transform API responses to internal models Implement circuit breakers for critical services Monitor API quota and rate limits Add proper error handling Use timeouts appropriately Test with sandbox/test API keys ❌ DON'T Hardcode API keys Retry all errors indefinitely Log sensitive data Trust unvalidated webhook data Ignore rate limits Make synchronous blocking calls Expose vendor-specific details to clients Skip error handling Use production keys in tests

返回排行榜