Build an API Gateway
Create a unified API gateway for all your integrations
Your company needs to integrate with Stripe for payments, SendGrid for emails, and Twilio for SMS notifications. The previous developer started but left incomplete code with no documentation. You need to build a unified notification system that handles payments, sends receipts via email, and notifies users via SMS - all with proper error handling and retry logic.
By completing this lesson, you’ll master:
Build a production-ready integration that:
Start with Ask mode to understand what exists:
@src/integrations"Analyze the existing integration code:- What APIs are partially implemented?- What's the current architecture?- What error handling exists?- What's missing for production use?- Security vulnerabilities?"
"Help me understand these APIs:- Stripe: Payment processing flow- SendGrid: Email API best practices- Twilio: SMS delivery guaranteesCreate a comparison of rate limits, auth methods, and error codes"
Switch to Agent mode:
"Design a unified notification system architecture:- Abstract interface for all notifications- Provider-specific implementations- Retry and fallback strategies- Configuration management- Error handling patternsCreate architecture diagram and interfaces"
Many APIs already have MCP servers available:
# GitHub MCP - Full GitHub API accessclaude mcp add --transport sse github https://api.githubcopilot.com/mcp/
# Linear MCP - Issue trackingclaude mcp add --transport sse linear https://mcp.linear.app/sse
# Jira MCP - Atlassian integration# Note: Atlassian's official endpoint is https://mcp.atlassian.com/v1/sse (Beta)# For local setup, use community packages:claude mcp add jira -- npx -y @mcp-devtools/jira
# Slack MCP - Messaging integrationclaude mcp add slack -- npx -y @modelcontextprotocol/server-slack
With GitHub MCP installed:
"Using GitHub MCP, show me:- How to create issues programmatically- Webhook setup for PR events- Rate limit handling- GraphQL query examples"
// MCP provides direct API access:"Create a GitHub issue in repo 'myorg/myrepo' with:- Title: 'Payment integration failing'- Labels: ['bug', 'high-priority']- Assignee: '@username'"
// Direct tool usage via MCP"Using Linear MCP:- Create issue in project 'API Integration'- Set priority to urgent- Add to current sprint"
// MCP handles:// - Authentication// - Rate limiting// - Error retry// - Response parsing
// Manual implementation neededconst linear = new LinearClient({ apiKey: process.env.LINEAR_API_KEY});
// You must implement:// - Error handling// - Retry logic// - Rate limiting// - Type definitions
"Coordinate between multiple MCP servers:1. When a Stripe payment succeeds (using our integration)2. Create a Linear issue for fulfillment (Linear MCP)3. Post to #sales Slack channel (Slack MCP)4. Update customer record in database"
// The AI can use multiple MCPs in sequence
"Using Context7 MCP, get the latest docs for:- Stripe Node.js SDK- SendGrid API v3- Twilio webhooks
Compare with our current implementation"
Use MCP Servers when:
Build Custom when:
"Create a base integration class with:- Retry logic with exponential backoff- Circuit breaker pattern- Request/response logging- Error standardization- Metrics collection- Rate limiting support"
Example base class:
export abstract class BaseIntegration { protected abstract readonly name: string; protected abstract readonly baseURL: string; protected abstract readonly maxRetries: number;
private circuitBreaker: CircuitBreaker; private metrics: MetricsCollector;
constructor(protected config: IntegrationConfig) { this.circuitBreaker = new CircuitBreaker({ timeout: config.timeout || 30000, errorThreshold: config.errorThreshold || 50, resetTimeout: config.resetTimeout || 60000 });
this.metrics = new MetricsCollector(this.name); }
protected async makeRequest<T>( method: string, endpoint: string, data?: any, options: RequestOptions = {} ): Promise<T> { const url = `${this.baseURL}${endpoint}`;
return this.circuitBreaker.execute(async () => { const startTime = Date.now();
try { const response = await this.executeWithRetry( method, url, data, options );
this.metrics.recordSuccess(Date.now() - startTime); return response; } catch (error) { this.metrics.recordError(error); throw this.standardizeError(error); } }); }
private async executeWithRetry<T>( method: string, url: string, data?: any, options: RequestOptions = {} ): Promise<T> { let lastError: Error;
for (let attempt = 0; attempt <= this.maxRetries; attempt++) { try { if (attempt > 0) { await this.delay(this.calculateBackoff(attempt)); }
return await this.executeRequest<T>(method, url, data, options); } catch (error) { lastError = error;
if (!this.isRetryable(error) || attempt === this.maxRetries) { throw error; }
logger.warn(`Retry attempt ${attempt + 1} for ${url}`, { error }); } }
throw lastError!; }
private calculateBackoff(attempt: number): number { const baseDelay = 1000; const maxDelay = 32000; const delay = Math.min(baseDelay * Math.pow(2, attempt), maxDelay); return delay + Math.random() * 1000; // Add jitter }
protected abstract isRetryable(error: any): boolean; protected abstract standardizeError(error: any): IntegrationError;}
@integrations/base.ts"Create provider implementations for:1. StripeIntegration extending BaseIntegration2. SendGridIntegration extending BaseIntegration3. TwilioIntegration extending BaseIntegrationInclude proper auth, error handling, and API-specific features"
"Create a NotificationService that:- Orchestrates all three services- Handles payment → email → SMS flow- Implements fallback strategies- Provides transaction-like behavior- Supports bulk operations"
"Create secure configuration management:- Environment-based config loading- Encrypted API key storage- Key rotation support- Configuration validation- Runtime config updates"
Example configuration:
export class IntegrationConfig { private static instance: IntegrationConfig; private configs: Map<string, ProviderConfig> = new Map();
private constructor() { this.loadConfigurations(); this.validateConfigurations(); this.setupKeyRotation(); }
static getInstance(): IntegrationConfig { if (!IntegrationConfig.instance) { IntegrationConfig.instance = new IntegrationConfig(); } return IntegrationConfig.instance; }
getConfig(provider: string): ProviderConfig { const config = this.configs.get(provider); if (!config) { throw new Error(`Configuration not found for provider: ${provider}`); }
// Decrypt API keys on demand return { ...config, apiKey: this.decryptKey(config.encryptedApiKey) }; }
private loadConfigurations() { // Load from environment variables or secure storage this.configs.set('stripe', { encryptedApiKey: process.env.STRIPE_API_KEY_ENCRYPTED!, webhookSecret: process.env.STRIPE_WEBHOOK_SECRET, apiVersion: '2023-10-16', timeout: 30000, maxRetries: 3 });
// Similar for SendGrid and Twilio }
private decryptKey(encryptedKey: string): string { // Implement secure decryption return decrypt(encryptedKey, process.env.MASTER_KEY!); }}
"Implement request security:- Webhook signature validation- Request signing for APIs that require it- API key rotation without downtime- OAuth token refresh logic- Rate limit header parsing"
"Create middleware for:- Input sanitization- Output filtering (remove sensitive data)- Request ID tracking- Audit logging- Threat detection"
"Create error handling system:- Categorize errors (rate limit, auth, network, etc.)- Implement appropriate retry strategies per type- Create fallback mechanisms- Dead letter queue for failed requests- Error recovery procedures"
Example error handling:
export class IntegrationError extends Error { constructor( message: string, public code: string, public provider: string, public isRetryable: boolean, public originalError?: any, public context?: Record<string, any> ) { super(message); this.name = 'IntegrationError'; }
static fromStripeError(error: any): IntegrationError { const retryableCodes = ['rate_limit', 'api_connection_error'];
return new IntegrationError( error.message || 'Stripe API error', error.code || 'unknown_error', 'stripe', retryableCodes.includes(error.code), error, { type: error.type, param: error.param, requestId: error.requestId } ); }
static fromSendGridError(error: any): IntegrationError { const isRetryable = error.code >= 500 || error.code === 429;
return new IntegrationError( error.message || 'SendGrid API error', `sendgrid_${error.code}`, 'sendgrid', isRetryable, error, { response: error.response?.body } ); }}
"Implement circuit breaker pattern:- Track failure rates per service- Open circuit on threshold breach- Half-open state for testing recovery- Configurable thresholds- Metrics and alerting"
"Implement fallback mechanisms:- Secondary email provider if SendGrid fails- SMS queue for Twilio outages- Cached responses for read operations- Graceful degradation strategies- User notification preferences"
@integrations"Generate tests for:- Unit tests with mocked APIs- Integration tests with sandbox APIs- Error scenario testing- Rate limit simulation- Circuit breaker behavior- Webhook handling"
Example test structure:
describe('StripeIntegration', () => { let stripe: StripeIntegration; let mockServer: MockServer;
beforeAll(async () => { mockServer = await createMockStripeServer(); stripe = new StripeIntegration({ apiKey: 'test_key', baseURL: mockServer.url }); });
describe('Payment Processing', () => { it('should handle successful payment', async () => { mockServer.onPost('/charges').reply(200, { id: 'ch_test123', status: 'succeeded' });
const result = await stripe.createCharge({ amount: 1000, currency: 'usd' });
expect(result.status).toBe('succeeded'); });
it('should retry on network errors', async () => { let attempts = 0; mockServer.onPost('/charges').reply(() => { attempts++; if (attempts < 3) { throw new NetworkError('Connection reset'); } return [200, { status: 'succeeded' }]; });
const result = await stripe.createCharge({ amount: 1000, currency: 'usd' });
expect(attempts).toBe(3); expect(result.status).toBe('succeeded'); }); });});
"Create monitoring system:- API response time tracking- Success/failure rates per endpoint- Rate limit usage monitoring- Error rate alerting- Cost tracking per service"
"Create debugging utilities:- Request/response replay tool- API call timeline visualization- Error pattern analysis- Performance profiling- Test data generators"
Let AI analyze API docs efficiently:
// Method 1: Using MCP servers (if available)"Using GitHub MCP, show me:- Repository API endpoints- Authentication patterns- Rate limiting details- Webhook configuration"
// Method 2: Using Context7 MCP for documentation"Using Context7 MCP, get the latest:- Stripe API reference- Best practices for idempotency- Webhook security guidelines"
// Method 3: Manual documentation analysis@stripe-api-docs.md"Extract key information:- Authentication method- Rate limits- Error codes and meanings- Idempotency support- Webhook eventsCreate a quick reference guide"
Ensure API compatibility:
"Generate contract tests from API documentation:- Request/response schemas- Required vs optional fields- Type definitions- Validation rules- Breaking change detection"
Implement smart retries:
// Different strategies for different errorsconst retryStrategies = { rate_limit: { shouldRetry: true, backoffMultiplier: 1, maxRetries: 10, respectRetryAfter: true }, network_error: { shouldRetry: true, backoffMultiplier: 2, maxRetries: 3, addJitter: true }, invalid_request: { shouldRetry: false }};
Problem: Hitting API rate limits during bulk operations
Solution:
// Implement token bucket algorithmclass RateLimiter { async executeWithRateLimit<T>( operation: () => Promise<T> ): Promise<T> { await this.acquireToken(); return operation(); }}
Problem: Webhook endpoints vulnerable to replay attacks
Solution:
// Validate signatures and timestampsfunction validateWebhook(payload, signature, timestamp) { if (Date.now() - timestamp > 300000) { // 5 minutes throw new Error('Webhook timestamp too old'); } // Verify signature}
Problem: Partial failures in multi-service operations
Solution:
// Implement saga pattern for distributed transactionsclass NotificationSaga { async execute(transaction: NotificationTransaction) { const steps = this.planSteps(transaction); const completed = [];
try { for (const step of steps) { await step.execute(); completed.push(step); } } catch (error) { // Compensate in reverse order for (const step of completed.reverse()) { await step.compensate(); } throw error; } }}
Enhance your integration system:
Multi-Provider Redundancy
Advanced Features
Performance Optimization
MCP Server Orchestration
Your integration is production-ready when:
Teams using these patterns report:
Before deploying:
You’ve mastered API integration patterns. Ready for more?
Build an API Gateway
Create a unified API gateway for all your integrations
Add GraphQL Layer
Build a GraphQL layer over REST APIs
Create SDK
Package your integrations as reusable SDKs
Continue to Database Design →