Advanced API Integration Patterns for Claude Code

This comprehensive guide explores advanced API integration patterns for Claude Code, covering GraphQL, WebSocket/SSE, gRPC, API gateways, rate limiting strategies, and event-driven architectures specifically designed for AI/LLM applications.

Overview

Modern AI applications require sophisticated API integration patterns to handle:

  • Real-time streaming responses
  • Complex microservice orchestration
  • High-throughput data processing
  • Multi-protocol communication
  • Scalable event-driven architectures

The patterns and code examples in this guide represent best practices for robust API design. These can be implemented efficiently using our project’s templating and scaffolding tools. For more details, see the AI-Powered Code Generation and Template Patterns guide.

Table of Contents

  1. GraphQL Integration with Claude Code
  2. WebSocket and Server-Sent Events (SSE) Patterns
  3. gRPC Service Integration
  4. API Gateway Patterns for Claude Services
  5. Rate Limiting and Quota Management Strategies
  6. Webhook Handling and Event-Driven Architectures

API Pattern Selection Guide

FeatureGraphQLWebSocket/SSEgRPC
Primary Use CaseFlexible data fetching, complex queriesReal-time, bidirectional communicationHigh-performance, low-latency RPC
Data ModelTyped schema, graph-basedMessage-based, unstructuredStrongly-typed contracts (Protobuf)
StreamingSubscriptions (server-to-client)Full bidirectional streamingFull bidirectional streaming
OverheadMedium (text-based, JSON)Low (persistent connection)Very Low (binary, HTTP/2)
Best for LLMsChained tool calls, complex data retrievalStreaming token-by-token responsesInternal microservice communication
ToolingExcellent (Apollo, Relay)Good (Socket.io, ws)Excellent (gRPC-web, BloomRPC)

1. GraphQL Integration with Claude Code

Why GraphQL for AI Applications?

GraphQL provides several advantages for AI-powered applications:

  • Efficient data fetching: Request only needed fields
  • Type safety: Strong typing for AI model inputs/outputs
  • Real-time subscriptions: Stream AI responses
  • Batching: Combine multiple AI requests

Basic GraphQL Schema for Claude Code

// schema.graphql
type Query {
  claudePrompt(input: ClaudePromptInput!): ClaudeResponse!
  claudeBatch(inputs: [ClaudePromptInput!]!): [ClaudeResponse!]!
  claudeSession(sessionId: ID!): ClaudeSession
}
 
type Mutation {
  createClaudeSession(config: SessionConfig!): ClaudeSession!
  sendPrompt(sessionId: ID!, prompt: String!): ClaudeResponse!
  clearSession(sessionId: ID!): Boolean!
}
 
type Subscription {
  claudeStream(sessionId: ID!): ClaudeStreamUpdate!
  sessionUpdates(sessionId: ID!): SessionUpdate!
}
 
input ClaudePromptInput {
  prompt: String!
  model: ClaudeModel
  maxTokens: Int
  temperature: Float
  systemPrompt: String
  tools: [String!]
}
 
enum ClaudeModel {
  CLAUDE_3_OPUS
  CLAUDE_3_SONNET
  CLAUDE_3_HAIKU
}
 
type ClaudeResponse {
  id: ID!
  content: String!
  usage: TokenUsage!
  metadata: ResponseMetadata!
  tools: [ToolCall!]
}
 
type ClaudeStreamUpdate {
  type: StreamEventType!
  delta: String
  toolCall: ToolCall
  metadata: StreamMetadata
}

GraphQL Resolver Implementation

// resolvers/claude.resolver.ts
import { GraphQLResolveInfo } from 'graphql';
import { Anthropic } from '@anthropic-ai/sdk';
import { PubSub } from 'graphql-subscriptions';
import DataLoader from 'dataloader';
 
export class ClaudeResolver {
  private anthropic: Anthropic;
  private pubsub: PubSub;
  private promptLoader: DataLoader<string, any>;
  
  constructor() {
    this.anthropic = new Anthropic();
    this.pubsub = new PubSub();
    
    // Batch loader for efficient API calls
    this.promptLoader = new DataLoader(async (prompts) => {
      const responses = await Promise.all(
        prompts.map(prompt => this.processPrompt(prompt))
      );
      return responses;
    });
  }
  
  // Query resolvers
  async claudePrompt(
    parent: any,
    args: { input: ClaudePromptInput },
    context: any,
    info: GraphQLResolveInfo
  ) {
    // Use field selection to optimize response
    const requestedFields = this.getRequestedFields(info);
    
    const response = await this.anthropic.messages.create({
      model: this.mapModel(args.input.model),
      messages: [{ role: 'user', content: args.input.prompt }],
      max_tokens: args.input.maxTokens || 1024,
      temperature: args.input.temperature || 0.7,
      system: args.input.systemPrompt
    });
    
    return this.formatResponse(response, requestedFields);
  }
  
  // Mutation resolvers
  async createClaudeSession(parent: any, args: any) {
    const sessionId = this.generateSessionId();
    const session = new ClaudeSession({
      id: sessionId,
      config: args.config,
      anthropic: this.anthropic
    });
    
    this.sessions.set(sessionId, session);
    
    return {
      id: sessionId,
      config: args.config,
      createdAt: new Date().toISOString(),
      status: 'active'
    };
  }
  
  // Subscription resolvers
  async *claudeStream(parent: any, args: { sessionId: string }) {
    const session = this.sessions.get(args.sessionId);
    if (!session) throw new Error('Session not found');
    
    const asyncIterator = this.pubsub.asyncIterator(
      `claude-stream-${args.sessionId}`
    );
    
    // Stream responses
    for await (const event of asyncIterator) {
      yield event;
    }
  }
  
  // Helper: Stream handler
  async streamResponse(sessionId: string, prompt: string) {
    const stream = await this.anthropic.messages.create({
      messages: [{ role: 'user', content: prompt }],
      model: 'claude-3-sonnet-20240229',
      stream: true
    });
    
    for await (const event of stream) {
      if (event.type === 'content_block_delta') {
        this.pubsub.publish(`claude-stream-${sessionId}`, {
          claudeStream: {
            type: 'CONTENT_DELTA',
            delta: event.delta.text
          }
        });
      }
    }
  }
}

GraphQL Federation for Microservices

// federation/claude-subgraph.ts
import { buildSubgraphSchema } from '@apollo/subgraph';
 
const typeDefs = gql`
  extend schema
    @link(url: "https://specs.apollo.dev/federation/v2.0",
          import: ["@key", "@shareable", "@external"])
  
  type ClaudeService @key(fields: "id") {
    id: ID!
    sessions: [ClaudeSession!]!
    usage: ServiceUsage!
  }
  
  type User @key(fields: "id", resolvable: false) {
    id: ID!
  }
  
  extend type User {
    claudeSessions: [ClaudeSession!]!
    claudeQuota: Quota!
  }
`;
 
export const claudeSubgraph = buildSubgraphSchema({
  typeDefs,
  resolvers: {
    User: {
      claudeSessions: async (user) => {
        return await sessionService.getSessionsByUserId(user.id);
      }
    }
  }
});

2. WebSocket and Server-Sent Events (SSE) Patterns

Bidirectional WebSocket Communication

// websocket/claude-ws-server.ts
import { WebSocketServer } from 'ws';
import { Anthropic } from '@anthropic-ai/sdk';
import { EventEmitter } from 'events';
 
interface WebSocketSession {
  id: string;
  ws: WebSocket;
  anthropic: Anthropic;
  context: Message[];
  activeStreams: Map<string, AbortController>;
}
 
export class ClaudeWebSocketServer extends EventEmitter {
  private wss: WebSocketServer;
  private sessions: Map<string, WebSocketSession> = new Map();
  private rateLimiter: RateLimiter;
  
  constructor(options: { port: number }) {
    super();
    this.wss = new WebSocketServer({ port: options.port });
    this.rateLimiter = new RateLimiter();
    this.setupHandlers();
  }
  
  private setupHandlers() {
    this.wss.on('connection', (ws, req) => {
      const sessionId = this.authenticate(req);
      if (!sessionId) {
        ws.close(1008, 'Unauthorized');
        return;
      }
      
      const session: WebSocketSession = {
        id: sessionId,
        ws,
        anthropic: new Anthropic(),
        context: [],
        activeStreams: new Map()
      };
      
      this.sessions.set(sessionId, session);
      
      ws.on('message', async (data) => {
        try {
          const message = JSON.parse(data.toString());
          await this.handleMessage(session, message);
        } catch (error) {
          this.sendError(ws, error);
        }
      });
      
      ws.on('close', () => {
        // Cleanup active streams
        session.activeStreams.forEach(controller => controller.abort());
        this.sessions.delete(sessionId);
      });
      
      // Send connection acknowledgment
      this.send(ws, {
        type: 'connection',
        sessionId,
        status: 'connected',
        timestamp: new Date().toISOString()
      });
    });
  }
  
  private async handleMessage(session: WebSocketSession, message: any) {
    // Rate limiting check
    const allowed = await this.rateLimiter.checkLimit(session.id);
    if (!allowed) {
      return this.send(session.ws, {
        type: 'error',
        error: 'Rate limit exceeded',
        retryAfter: 60
      });
    }
    
    switch (message.type) {
      case 'prompt':
        await this.handlePrompt(session, message);
        break;
        
      case 'stop':
        this.stopStream(session, message.streamId);
        break;
        
      case 'clear_context':
        session.context = [];
        this.send(session.ws, { type: 'context_cleared' });
        break;
        
      case 'tool_result':
        await this.handleToolResult(session, message);
        break;
    }
  }
  
  private async handlePrompt(session: WebSocketSession, message: any) {
    const streamId = this.generateStreamId();
    const controller = new AbortController();
    session.activeStreams.set(streamId, controller);
    
    try {
      const stream = await session.anthropic.messages.create({
        messages: [
          ...session.context,
          { role: 'user', content: message.prompt }
        ],
        model: message.model || 'claude-3-sonnet-20240229',
        max_tokens: message.maxTokens || 1024,
        stream: true,
        tools: message.tools
      }, {
        signal: controller.signal
      });
      
      let fullResponse = '';
      let currentToolUse: any = null;
      
      for await (const event of stream) {
        if (controller.signal.aborted) break;
        
        switch (event.type) {
          case 'content_block_start':
            if (event.content_block.type === 'tool_use') {
              currentToolUse = {
                id: event.content_block.id,
                name: event.content_block.name,
                input: ''
              };
            }
            break;
            
          case 'content_block_delta':
            if (event.delta.type === 'text_delta') {
              fullResponse += event.delta.text;
              this.send(session.ws, {
                type: 'stream_delta',
                streamId,
                delta: event.delta.text
              });
            } else if (event.delta.type === 'input_json_delta') {
              if (currentToolUse) {
                currentToolUse.input += event.delta.partial_json;
              }
            }
            break;
            
          case 'content_block_stop':
            if (currentToolUse) {
              this.send(session.ws, {
                type: 'tool_use',
                streamId,
                tool: {
                  id: currentToolUse.id,
                  name: currentToolUse.name,
                  input: JSON.parse(currentToolUse.input)
                }
              });
              currentToolUse = null;
            }
            break;
            
          case 'message_stop':
            // Update context
            session.context.push(
              { role: 'user', content: message.prompt },
              { role: 'assistant', content: fullResponse }
            );
            
            this.send(session.ws, {
              type: 'stream_complete',
              streamId,
              usage: event.usage
            });
            
            session.activeStreams.delete(streamId);
            break;
        }
      }
    } catch (error) {
      session.activeStreams.delete(streamId);
      this.sendError(session.ws, error, streamId);
    }
  }
  
  private stopStream(session: WebSocketSession, streamId: string) {
    const controller = session.activeStreams.get(streamId);
    if (controller) {
      controller.abort();
      session.activeStreams.delete(streamId);
      this.send(session.ws, {
        type: 'stream_stopped',
        streamId
      });
    }
  }
}

Server-Sent Events for Unidirectional Streaming

// sse/claude-sse-server.ts
import express from 'express';
import { Anthropic } from '@anthropic-ai/sdk';
 
export class ClaudeSSEServer {
  private app: express.Application;
  private anthropic: Anthropic;
  private activeConnections: Map<string, Response> = new Map();
  
  constructor() {
    this.app = express();
    this.anthropic = new Anthropic();
    this.setupRoutes();
  }
  
  private setupRoutes() {
    // SSE endpoint for streaming Claude responses
    this.app.get('/sse/claude-stream', async (req, res) => {
      // Set SSE headers
      res.writeHead(200, {
        'Content-Type': 'text/event-stream',
        'Cache-Control': 'no-cache',
        'Connection': 'keep-alive',
        'X-Accel-Buffering': 'no' // Disable Nginx buffering
      });
      
      const connectionId = this.generateConnectionId();
      this.activeConnections.set(connectionId, res);
      
      // Send initial connection event
      this.sendSSE(res, {
        event: 'connected',
        data: { connectionId, timestamp: new Date().toISOString() }
      });
      
      // Handle connection close
      req.on('close', () => {
        this.activeConnections.delete(connectionId);
      });
      
      // Keep connection alive
      const keepAlive = setInterval(() => {
        res.write(':ping\n\n');
      }, 30000);
      
      req.on('close', () => clearInterval(keepAlive));
    });
    
    // Endpoint to trigger Claude streaming
    this.app.post('/api/claude-prompt', express.json(), async (req, res) => {
      const { connectionId, prompt, options = {} } = req.body;
      
      const sseConnection = this.activeConnections.get(connectionId);
      if (!sseConnection) {
        return res.status(404).json({ error: 'Connection not found' });
      }
      
      try {
        await this.streamToConnection(sseConnection, prompt, options);
        res.json({ success: true });
      } catch (error) {
        res.status(500).json({ error: error.message });
      }
    });
  }
  
  private async streamToConnection(
    connection: Response,
    prompt: string,
    options: any
  ) {
    const stream = await this.anthropic.messages.create({
      messages: [{ role: 'user', content: prompt }],
      model: options.model || 'claude-3-sonnet-20240229',
      max_tokens: options.maxTokens || 1024,
      stream: true
    });
    
    let buffer = '';
    let tokenCount = 0;
    
    for await (const event of stream) {
      if (event.type === 'content_block_delta') {
        buffer += event.delta.text;
        tokenCount++;
        
        // Send in chunks to optimize network usage
        if (buffer.length > 100 || tokenCount % 10 === 0) {
          this.sendSSE(connection, {
            event: 'delta',
            data: {
              content: buffer,
              tokens: tokenCount
            }
          });
          buffer = '';
        }
      } else if (event.type === 'message_stop') {
        // Send any remaining buffer
        if (buffer) {
          this.sendSSE(connection, {
            event: 'delta',
            data: { content: buffer, tokens: tokenCount }
          });
        }
        
        this.sendSSE(connection, {
          event: 'complete',
          data: { 
            usage: event.usage,
            totalTokens: tokenCount
          }
        });
      }
    }
  }
  
  private sendSSE(res: Response, payload: { event: string; data: any }) {
    res.write(`event: ${payload.event}\n`);
    res.write(`data: ${JSON.stringify(payload.data)}\n\n`);
  }
}

3. gRPC Service Integration

gRPC Protocol Definition

// proto/claude.proto
syntax = "proto3";
 
package claude;
 
service ClaudeService {
  // Unary RPC for simple requests
  rpc SendPrompt(PromptRequest) returns (PromptResponse);
  
  // Server streaming for real-time responses
  rpc StreamPrompt(PromptRequest) returns (stream StreamResponse);
  
  // Bidirectional streaming for interactive sessions
  rpc InteractiveSession(stream SessionMessage) returns (stream SessionResponse);
  
  // Batch processing
  rpc BatchProcess(BatchRequest) returns (BatchResponse);
}
 
message PromptRequest {
  string prompt = 1;
  string model = 2;
  int32 max_tokens = 3;
  float temperature = 4;
  repeated Tool tools = 5;
  map<string, string> metadata = 6;
}
 
message PromptResponse {
  string id = 1;
  string content = 2;
  Usage usage = 3;
  repeated ToolCall tool_calls = 4;
}
 
message StreamResponse {
  oneof event {
    ContentDelta content_delta = 1;
    ToolUse tool_use = 2;
    StreamComplete complete = 3;
    StreamError error = 4;
  }
}
 
message SessionMessage {
  oneof message {
    StartSession start = 1;
    UserPrompt prompt = 2;
    ToolResult tool_result = 3;
    EndSession end = 4;
  }
}
 
message Tool {
  string name = 1;
  string description = 2;
  Parameters parameters = 3;
}
 
message Usage {
  int32 input_tokens = 1;
  int32 output_tokens = 2;
  int32 total_tokens = 3;
}

gRPC Server Implementation

// grpc/claude-grpc-server.ts
import * as grpc from '@grpc/grpc-js';
import * as protoLoader from '@grpc/proto-loader';
import { Anthropic } from '@anthropic-ai/sdk';
import { CircuitBreaker } from 'opossum';
 
const PROTO_PATH = './proto/claude.proto';
 
export class ClaudeGrpcServer {
  private server: grpc.Server;
  private anthropic: Anthropic;
  private circuitBreaker: CircuitBreaker;
  
  constructor() {
    this.server = new grpc.Server();
    this.anthropic = new Anthropic();
    
    // Circuit breaker for resilience
    this.circuitBreaker = new CircuitBreaker(
      this.callClaude.bind(this),
      {
        timeout: 30000,
        errorThresholdPercentage: 50,
        resetTimeout: 30000
      }
    );
    
    this.loadProtoAndStart();
  }
  
  private async loadProtoAndStart() {
    const packageDefinition = protoLoader.loadSync(PROTO_PATH, {
      keepCase: true,
      longs: String,
      enums: String,
      defaults: true,
      oneofs: true
    });
    
    const claudeProto = grpc.loadPackageDefinition(packageDefinition).claude;
    
    this.server.addService(claudeProto.ClaudeService.service, {
      sendPrompt: this.sendPrompt.bind(this),
      streamPrompt: this.streamPrompt.bind(this),
      interactiveSession: this.interactiveSession.bind(this),
      batchProcess: this.batchProcess.bind(this)
    });
    
    // Add interceptors
    this.server.addService(claudeProto.ClaudeService.service, {
      sendPrompt: this.withInterceptors(this.sendPrompt.bind(this))
    });
  }
  
  // Unary RPC implementation
  private async sendPrompt(
    call: grpc.ServerUnaryCall<any, any>,
    callback: grpc.sendUnaryData<any>
  ) {
    try {
      const metadata = this.extractMetadata(call.metadata);
      
      // Validate request
      if (!this.validateRequest(call.request)) {
        return callback({
          code: grpc.status.INVALID_ARGUMENT,
          message: 'Invalid request parameters'
        });
      }
      
      // Use circuit breaker
      const response = await this.circuitBreaker.fire(call.request);
      
      callback(null, response);
    } catch (error) {
      this.handleError(error, callback);
    }
  }
  
  // Server streaming implementation
  private async streamPrompt(call: grpc.ServerWritableStream<any, any>) {
    try {
      const stream = await this.anthropic.messages.create({
        messages: [{ role: 'user', content: call.request.prompt }],
        model: call.request.model || 'claude-3-sonnet-20240229',
        max_tokens: call.request.max_tokens || 1024,
        stream: true
      });
      
      for await (const event of stream) {
        if (call.cancelled) break;
        
        if (event.type === 'content_block_delta') {
          call.write({
            content_delta: {
              text: event.delta.text
            }
          });
        } else if (event.type === 'message_stop') {
          call.write({
            complete: {
              usage: {
                input_tokens: event.usage.input_tokens,
                output_tokens: event.usage.output_tokens,
                total_tokens: event.usage.input_tokens + event.usage.output_tokens
              }
            }
          });
          call.end();
        }
      }
    } catch (error) {
      call.emit('error', this.grpcError(error));
    }
  }
  
  // Bidirectional streaming implementation
  private interactiveSession(
    call: grpc.ServerDuplexStream<any, any>
  ) {
    const session = {
      id: this.generateSessionId(),
      context: [],
      anthropic: new Anthropic()
    };
    
    call.on('data', async (message) => {
      try {
        if (message.start) {
          call.write({
            session_started: {
              session_id: session.id,
              timestamp: new Date().toISOString()
            }
          });
        } else if (message.prompt) {
          await this.handleSessionPrompt(call, session, message.prompt);
        } else if (message.tool_result) {
          await this.handleToolResult(call, session, message.tool_result);
        } else if (message.end) {
          call.end();
        }
      } catch (error) {
        call.emit('error', this.grpcError(error));
      }
    });
    
    call.on('end', () => {
      // Cleanup session
      call.end();
    });
  }
  
  // Batch processing with parallel execution
  private async batchProcess(
    call: grpc.ServerUnaryCall<any, any>,
    callback: grpc.sendUnaryData<any>
  ) {
    try {
      const { requests, parallel_limit = 5 } = call.request;
      
      // Process in batches with concurrency limit
      const results = [];
      for (let i = 0; i < requests.length; i += parallel_limit) {
        const batch = requests.slice(i, i + parallel_limit);
        const batchResults = await Promise.all(
          batch.map(req => this.processWithRetry(req))
        );
        results.push(...batchResults);
      }
      
      callback(null, {
        responses: results,
        total_processed: results.length,
        timestamp: new Date().toISOString()
      });
    } catch (error) {
      this.handleError(error, callback);
    }
  }
  
  // Helper: Add interceptors for logging, auth, etc.
  private withInterceptors(handler: Function) {
    return async (call: any, callback: any) => {
      // Logging interceptor
      console.log(`gRPC call: ${call.getPeer()} - ${new Date().toISOString()}`);
      
      // Auth interceptor
      const authToken = call.metadata.get('authorization')[0];
      if (!this.validateAuth(authToken)) {
        return callback({
          code: grpc.status.UNAUTHENTICATED,
          message: 'Invalid authentication'
        });
      }
      
      // Rate limiting interceptor
      const clientId = this.extractClientId(call.metadata);
      if (!await this.rateLimiter.checkLimit(clientId)) {
        return callback({
          code: grpc.status.RESOURCE_EXHAUSTED,
          message: 'Rate limit exceeded'
        });
      }
      
      // Execute handler
      return handler(call, callback);
    };
  }
  
  // Start the server
  start(port: number) {
    this.server.bindAsync(
      `0.0.0.0:${port}`,
      grpc.ServerCredentials.createInsecure(),
      (err, port) => {
        if (err) {
          console.error('Failed to start gRPC server:', err);
          return;
        }
        
        console.log(`Claude gRPC server running on port ${port}`);
        this.server.start();
      }
    );
  }
}

gRPC Client with Load Balancing

// grpc/claude-grpc-client.ts
import * as grpc from '@grpc/grpc-js';
import * as protoLoader from '@grpc/proto-loader';
 
export class ClaudeGrpcClient {
  private clients: any[];
  private currentIndex: number = 0;
  
  constructor(servers: string[]) {
    const packageDefinition = protoLoader.loadSync('./proto/claude.proto');
    const claudeProto = grpc.loadPackageDefinition(packageDefinition).claude;
    
    // Create clients with load balancing
    this.clients = servers.map(server => 
      new claudeProto.ClaudeService(
        server,
        grpc.credentials.createInsecure(),
        {
          'grpc.keepalive_time_ms': 120000,
          'grpc.http2.min_time_between_pings_ms': 120000,
          'grpc.keepalive_timeout_ms': 20000,
          'grpc.http2.max_pings_without_data': 0,
          'grpc.keepalive_permit_without_calls': 1
        }
      )
    );
  }
  
  // Round-robin load balancing
  private getClient() {
    const client = this.clients[this.currentIndex];
    this.currentIndex = (this.currentIndex + 1) % this.clients.length;
    return client;
  }
  
  async sendPrompt(request: any): Promise<any> {
    return new Promise((resolve, reject) => {
      const client = this.getClient();
      const deadline = new Date();
      deadline.setSeconds(deadline.getSeconds() + 30);
      
      client.sendPrompt(request, { deadline }, (error, response) => {
        if (error) {
          // Retry with another server
          if (error.code === grpc.status.UNAVAILABLE) {
            const nextClient = this.getClient();
            return nextClient.sendPrompt(request, { deadline }, 
              (err, res) => err ? reject(err) : resolve(res)
            );
          }
          reject(error);
        } else {
          resolve(response);
        }
      });
    });
  }
  
  streamPrompt(request: any): grpc.ClientReadableStream<any> {
    const client = this.getClient();
    return client.streamPrompt(request);
  }
}

4. API Gateway Patterns for Claude Services

Kong Gateway Configuration

# kong/claude-gateway.yaml
_format_version: "3.0"
 
services:
  - name: claude-api
    url: http://claude-backend:3000
    plugins:
      - name: rate-limiting
        config:
          minute: 60
          hour: 1000
          policy: local
          
      - name: request-transformer
        config:
          add:
            headers:
              - X-Claude-Version:v1
              
      - name: response-transformer
        config:
          add:
            headers:
              - X-Response-Time:$(latency)
              
      - name: correlation-id
        config:
          header_name: X-Request-ID
          generator: uuid
          
    routes:
      - name: claude-route
        paths:
          - /api/claude
        methods:
          - GET
          - POST
          
  - name: claude-graphql
    url: http://claude-graphql:4000
    plugins:
      - name: graphql-rate-limiting
        config:
          cost_strategy:
            query: 1
            mutation: 10
            subscription: 5
            
    routes:
      - name: graphql-route
        paths:
          - /graphql
          
  - name: claude-grpc
    url: grpc://claude-grpc:50051
    protocol: grpc
    plugins:
      - name: grpc-gateway
        config:
          proto: /usr/local/kong/claude.proto
          
    routes:
      - name: grpc-route
        paths:
          - /grpc/claude

Custom API Gateway Implementation

// gateway/claude-api-gateway.ts
import express from 'express';
import httpProxy from 'http-proxy-middleware';
import jwt from 'jsonwebtoken';
import { RateLimiter } from './rate-limiter';
import { CircuitBreaker } from './circuit-breaker';
import { Cache } from './cache';
 
interface ServiceEndpoint {
  name: string;
  url: string;
  healthCheck: string;
  weight: number;
  circuitBreaker: CircuitBreaker;
}
 
export class ClaudeAPIGateway {
  private app: express.Application;
  private services: Map<string, ServiceEndpoint[]> = new Map();
  private rateLimiter: RateLimiter;
  private cache: Cache;
  
  constructor() {
    this.app = express();
    this.rateLimiter = new RateLimiter();
    this.cache = new Cache();
    this.setupMiddleware();
    this.registerServices();
  }
  
  private setupMiddleware() {
    // Request ID
    this.app.use((req, res, next) => {
      req.id = req.headers['x-request-id'] || this.generateRequestId();
      res.setHeader('X-Request-ID', req.id);
      next();
    });
    
    // Authentication
    this.app.use('/api/*', this.authenticate.bind(this));
    
    // Rate limiting
    this.app.use('/api/*', this.rateLimit.bind(this));
    
    // Request logging
    this.app.use(this.logRequest.bind(this));
    
    // CORS
    this.app.use((req, res, next) => {
      res.header('Access-Control-Allow-Origin', '*');
      res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
      res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
      next();
    });
  }
  
  private registerServices() {
    // Claude main API
    this.addService('claude-api', [
      {
        name: 'claude-1',
        url: 'http://claude-1:3000',
        healthCheck: '/health',
        weight: 1,
        circuitBreaker: new CircuitBreaker({ threshold: 5, timeout: 60000 })
      },
      {
        name: 'claude-2',
        url: 'http://claude-2:3000',
        healthCheck: '/health',
        weight: 1,
        circuitBreaker: new CircuitBreaker({ threshold: 5, timeout: 60000 })
      }
    ]);
    
    // GraphQL endpoint
    this.addService('graphql', [
      {
        name: 'graphql-1',
        url: 'http://graphql:4000',
        healthCheck: '/health',
        weight: 1,
        circuitBreaker: new CircuitBreaker({ threshold: 3, timeout: 30000 })
      }
    ]);
    
    // Setup routes
    this.setupRoutes();
  }
  
  private setupRoutes() {
    // Claude API routes
    this.app.use('/api/claude', this.createProxy('claude-api', {
      pathRewrite: { '^/api/claude': '' },
      onProxyReq: this.onProxyReq.bind(this),
      onProxyRes: this.onProxyRes.bind(this)
    }));
    
    // GraphQL route with special handling
    this.app.use('/graphql', this.createGraphQLProxy());
    
    // WebSocket upgrade for real-time
    this.app.use('/ws', this.createWebSocketProxy());
    
    // Health check endpoint
    this.app.get('/health', this.healthCheck.bind(this));
    
    // Metrics endpoint
    this.app.get('/metrics', this.getMetrics.bind(this));
  }
  
  private createProxy(serviceName: string, options: any) {
    return async (req, res, next) => {
      const endpoint = await this.selectEndpoint(serviceName);
      if (!endpoint) {
        return res.status(503).json({ error: 'Service unavailable' });
      }
      
      // Check circuit breaker
      if (endpoint.circuitBreaker.isOpen()) {
        const nextEndpoint = await this.selectEndpoint(serviceName, endpoint);
        if (!nextEndpoint) {
          return res.status(503).json({ error: 'All services unavailable' });
        }
        endpoint = nextEndpoint;
      }
      
      // Check cache for GET requests
      if (req.method === 'GET') {
        const cached = await this.cache.get(req.originalUrl);
        if (cached) {
          return res.json(cached);
        }
      }
      
      // Create proxy
      const proxy = httpProxy.createProxyMiddleware({
        target: endpoint.url,
        changeOrigin: true,
        ...options,
        onError: (err, req, res) => {
          endpoint.circuitBreaker.recordFailure();
          this.handleProxyError(err, req, res);
        },
        onProxyRes: (proxyRes, req, res) => {
          endpoint.circuitBreaker.recordSuccess();
          if (options.onProxyRes) {
            options.onProxyRes(proxyRes, req, res);
          }
        }
      });
      
      proxy(req, res, next);
    };
  }
  
  private async selectEndpoint(
    serviceName: string,
    exclude?: ServiceEndpoint
  ): Promise<ServiceEndpoint | null> {
    const endpoints = this.services.get(serviceName) || [];
    const available = endpoints.filter(e => 
      e !== exclude && !e.circuitBreaker.isOpen()
    );
    
    if (available.length === 0) return null;
    
    // Weighted random selection
    const totalWeight = available.reduce((sum, e) => sum + e.weight, 0);
    let random = Math.random() * totalWeight;
    
    for (const endpoint of available) {
      random -= endpoint.weight;
      if (random <= 0) return endpoint;
    }
    
    return available[0];
  }
  
  private async authenticate(req, res, next) {
    const token = req.headers.authorization?.split(' ')[1];
    if (!token) {
      return res.status(401).json({ error: 'No token provided' });
    }
    
    try {
      const decoded = jwt.verify(token, process.env.JWT_SECRET);
      req.user = decoded;
      next();
    } catch (error) {
      res.status(401).json({ error: 'Invalid token' });
    }
  }
  
  private async rateLimit(req, res, next) {
    const key = req.user?.id || req.ip;
    const allowed = await this.rateLimiter.checkLimit(key);
    
    if (!allowed) {
      return res.status(429).json({
        error: 'Rate limit exceeded',
        retryAfter: 60
      });
    }
    
    next();
  }
  
  private createGraphQLProxy() {
    return async (req, res, next) => {
      // GraphQL-specific handling
      if (req.body?.query) {
        const complexity = this.calculateQueryComplexity(req.body.query);
        if (complexity > 1000) {
          return res.status(400).json({
            error: 'Query too complex'
          });
        }
      }
      
      // Use the standard proxy
      return this.createProxy('graphql', {
        pathRewrite: { '^/graphql': '/graphql' }
      })(req, res, next);
    };
  }
  
  private async healthCheck(req, res) {
    const health = {
      status: 'healthy',
      services: {},
      timestamp: new Date().toISOString()
    };
    
    // Check all services
    for (const [name, endpoints] of this.services) {
      health.services[name] = await Promise.all(
        endpoints.map(async endpoint => ({
          name: endpoint.name,
          url: endpoint.url,
          healthy: await this.checkEndpointHealth(endpoint),
          circuitBreaker: endpoint.circuitBreaker.getState()
        }))
      );
    }
    
    res.json(health);
  }
  
  start(port: number) {
    this.app.listen(port, () => {
      console.log(`API Gateway running on port ${port}`);
    });
  }
}

5. Rate Limiting and Quota Management Strategies

Advanced Rate Limiting Implementation

// rate-limiting/advanced-rate-limiter.ts
import Redis from 'ioredis';
import { TokenBucket } from './token-bucket';
 
interface RateLimitRule {
  name: string;
  limit: number;
  window: number;
  cost?: (request: any) => number;
}
 
export class AdvancedRateLimiter {
  private redis: Redis;
  private rules: Map<string, RateLimitRule> = new Map();
  private buckets: Map<string, TokenBucket> = new Map();
  
  constructor(redisUrl: string) {
    this.redis = new Redis(redisUrl);
    this.setupDefaultRules();
  }
  
  private setupDefaultRules() {
    // API key-based limits
    this.addRule('api-key-minute', { limit: 60, window: 60 });
    this.addRule('api-key-hour', { limit: 1000, window: 3600 });
    this.addRule('api-key-day', { limit: 10000, window: 86400 });
    
    // Model-specific limits
    this.addRule('opus-minute', { limit: 10, window: 60 });
    this.addRule('sonnet-minute', { limit: 30, window: 60 });
    this.addRule('haiku-minute', { limit: 100, window: 60 });
    
    // Token-based limits
    this.addRule('tokens-minute', { 
      limit: 100000, 
      window: 60,
      cost: (req) => req.estimatedTokens || 1000
    });
    
    // Endpoint-specific limits
    this.addRule('embedding-minute', { limit: 200, window: 60 });
    this.addRule('batch-hour', { limit: 50, window: 3600 });
  }
  
  async checkLimit(
    key: string,
    request: any,
    rules: string[] = ['api-key-minute']
  ): Promise<RateLimitResult> {
    const results = await Promise.all(
      rules.map(ruleName => this.checkRule(key, ruleName, request))
    );
    
    // Find the most restrictive limit
    const blocked = results.find(r => !r.allowed);
    if (blocked) return blocked;
    
    // Return the limit with least remaining
    return results.reduce((min, current) => 
      current.remaining < min.remaining ? current : min
    );
  }
  
  private async checkRule(
    key: string,
    ruleName: string,
    request: any
  ): Promise<RateLimitResult> {
    const rule = this.rules.get(ruleName);
    if (!rule) throw new Error(`Unknown rule: ${ruleName}`);
    
    const cost = rule.cost ? rule.cost(request) : 1;
    const bucketKey = `${key}:${ruleName}`;
    
    // Use Redis for distributed rate limiting
    const result = await this.redisCheckLimit(
      bucketKey,
      rule.limit,
      rule.window,
      cost
    );
    
    return {
      allowed: result.allowed,
      limit: rule.limit,
      remaining: result.remaining,
      reset: result.reset,
      retryAfter: result.allowed ? 0 : result.reset - Date.now()
    };
  }
  
  private async redisCheckLimit(
    key: string,
    limit: number,
    window: number,
    cost: number
  ): Promise<any> {
    const now = Date.now();
    const clearBefore = now - window * 1000;
    
    const pipeline = this.redis.pipeline();
    
    // Remove old entries
    pipeline.zremrangebyscore(key, '-inf', clearBefore);
    
    // Count current entries
    pipeline.zcard(key);
    
    // Get the oldest entry
    pipeline.zrange(key, 0, 0, 'WITHSCORES');
    
    const results = await pipeline.exec();
    
    const currentCount = results[1][1] as number;
    const oldestEntry = results[2][1] as any[];
    
    if (currentCount + cost > limit) {
      // Calculate when the oldest entry expires
      const reset = oldestEntry.length > 0 
        ? parseInt(oldestEntry[1]) + window * 1000 
        : now + window * 1000;
        
      return {
        allowed: false,
        remaining: Math.max(0, limit - currentCount),
        reset
      };
    }
    
    // Add new entries
    const addPipeline = this.redis.pipeline();
    for (let i = 0; i < cost; i++) {
      addPipeline.zadd(key, now, `${now}-${i}`);
    }
    addPipeline.expire(key, window);
    await addPipeline.exec();
    
    return {
      allowed: true,
      remaining: limit - currentCount - cost,
      reset: now + window * 1000
    };
  }
  
  // Adaptive rate limiting based on system load
  async adaptiveLimitCheck(
    key: string,
    request: any
  ): Promise<RateLimitResult> {
    const systemLoad = await this.getSystemLoad();
    
    // Adjust limits based on load
    let adjustedRules = ['api-key-minute'];
    if (systemLoad > 0.8) {
      adjustedRules = ['api-key-minute-strict'];
    } else if (systemLoad < 0.3) {
      adjustedRules = ['api-key-minute-relaxed'];
    }
    
    return this.checkLimit(key, request, adjustedRules);
  }
  
  // Quota management
  async checkQuota(
    userId: string,
    tokensRequested: number
  ): Promise<QuotaResult> {
    const quotaKey = `quota:${userId}`;
    const quotaInfo = await this.redis.hgetall(quotaKey);
    
    const dailyLimit = parseInt(quotaInfo.dailyLimit) || 100000;
    const monthlyLimit = parseInt(quotaInfo.monthlyLimit) || 1000000;
    const dailyUsed = parseInt(quotaInfo.dailyUsed) || 0;
    const monthlyUsed = parseInt(quotaInfo.monthlyUsed) || 0;
    
    if (dailyUsed + tokensRequested > dailyLimit) {
      return {
        allowed: false,
        reason: 'Daily quota exceeded',
        dailyRemaining: dailyLimit - dailyUsed,
        monthlyRemaining: monthlyLimit - monthlyUsed
      };
    }
    
    if (monthlyUsed + tokensRequested > monthlyLimit) {
      return {
        allowed: false,
        reason: 'Monthly quota exceeded',
        dailyRemaining: dailyLimit - dailyUsed,
        monthlyRemaining: monthlyLimit - monthlyUsed
      };
    }
    
    // Update usage
    await this.redis.hincrby(quotaKey, 'dailyUsed', tokensRequested);
    await this.redis.hincrby(quotaKey, 'monthlyUsed', tokensRequested);
    
    return {
      allowed: true,
      dailyRemaining: dailyLimit - dailyUsed - tokensRequested,
      monthlyRemaining: monthlyLimit - monthlyUsed - tokensRequested
    };
  }
}

6. Webhook Handling and Event-Driven Architectures

Webhook Server with Event Processing

// webhooks/claude-webhook-server.ts
import express from 'express';
import { EventEmitter } from 'events';
import crypto from 'crypto';
import { Queue } from 'bull';
 
interface WebhookConfig {
  url: string;
  events: string[];
  secret: string;
  retries: number;
  timeout: number;
}
 
export class ClaudeWebhookServer extends EventEmitter {
  private app: express.Application;
  private webhooks: Map<string, WebhookConfig> = new Map();
  private eventQueue: Queue;
  private processingQueue: Queue;
  
  constructor() {
    super();
    this.app = express();
    this.eventQueue = new Queue('webhook-events');
    this.processingQueue = new Queue('webhook-processing');
    this.setupRoutes();
    this.setupQueues();
  }
  
  private setupRoutes() {
    // Webhook registration endpoint
    this.app.post('/webhooks/register', express.json(), async (req, res) => {
      const { url, events, secret } = req.body;
      
      const id = this.generateWebhookId();
      const config: WebhookConfig = {
        url,
        events,
        secret,
        retries: 3,
        timeout: 30000
      };
      
      this.webhooks.set(id, config);
      
      res.json({
        id,
        status: 'registered',
        events,
        createdAt: new Date().toISOString()
      });
    });
    
    // Webhook receiver for external events
    this.app.post('/webhooks/receive/:source', express.raw({ type: '*/*' }), 
      async (req, res) => {
        const source = req.params.source;
        const signature = req.headers['x-webhook-signature'];
        
        // Verify signature
        if (!this.verifyWebhookSignature(req.body, signature, source)) {
          return res.status(401).json({ error: 'Invalid signature' });
        }
        
        // Queue event for processing
        await this.eventQueue.add('process-webhook', {
          source,
          headers: req.headers,
          body: req.body,
          timestamp: new Date().toISOString()
        });
        
        res.status(202).json({ status: 'accepted' });
      }
    );
    
    // Event trigger endpoint (internal)
    this.app.post('/events/trigger', express.json(), async (req, res) => {
      const { event, data } = req.body;
      
      await this.triggerWebhooks(event, data);
      
      res.json({ status: 'triggered', event });
    });
  }
  
  private setupQueues() {
    // Process incoming webhook events
    this.eventQueue.process('process-webhook', async (job) => {
      const { source, body, headers } = job.data;
      
      try {
        // Parse and validate event
        const event = this.parseWebhookEvent(source, body);
        
        // Emit for local handling
        this.emit(`webhook:${source}`, event);
        
        // Process with Claude if needed
        if (event.requiresAI) {
          await this.processWithClaude(event);
        }
        
        // Trigger outgoing webhooks
        await this.triggerWebhooks(event.type, event);
        
      } catch (error) {
        console.error('Webhook processing error:', error);
        throw error;
      }
    });
    
    // Process outgoing webhooks
    this.processingQueue.process('send-webhook', async (job) => {
      const { webhookId, event, data } = job.data;
      const config = this.webhooks.get(webhookId);
      
      if (!config) return;
      
      try {
        await this.sendWebhook(config, event, data);
      } catch (error) {
        // Retry logic handled by Bull
        throw error;
      }
    });
  }
  
  private async triggerWebhooks(event: string, data: any) {
    const tasks = [];
    
    for (const [id, config] of this.webhooks) {
      if (config.events.includes(event) || config.events.includes('*')) {
        tasks.push(
          this.processingQueue.add('send-webhook', {
            webhookId: id,
            event,
            data
          }, {
            attempts: config.retries,
            backoff: {
              type: 'exponential',
              delay: 2000
            }
          })
        );
      }
    }
    
    await Promise.all(tasks);
  }
  
  private async sendWebhook(
    config: WebhookConfig,
    event: string,
    data: any
  ) {
    const payload = {
      event,
      data,
      timestamp: new Date().toISOString(),
      id: this.generateEventId()
    };
    
    const signature = this.generateSignature(payload, config.secret);
    
    const response = await fetch(config.url, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-Webhook-Event': event,
        'X-Webhook-Signature': signature,
        'X-Webhook-ID': payload.id
      },
      body: JSON.stringify(payload),
      signal: AbortSignal.timeout(config.timeout)
    });
    
    if (!response.ok) {
      throw new Error(`Webhook failed: ${response.status}`);
    }
    
    // Log successful delivery
    this.emit('webhook:delivered', {
      webhookId: config.url,
      event,
      responseStatus: response.status
    });
  }
  
  private generateSignature(payload: any, secret: string): string {
    return crypto
      .createHmac('sha256', secret)
      .update(JSON.stringify(payload))
      .digest('hex');
  }
  
  private verifyWebhookSignature(
    body: Buffer,
    signature: string,
    source: string
  ): boolean {
    // Implementation depends on source
    switch (source) {
      case 'github':
        return this.verifyGitHubSignature(body, signature);
      case 'stripe':
        return this.verifyStripeSignature(body, signature);
      default:
        return true; // Or implement generic verification
    }
  }
}

Event-Driven Architecture with Kafka

// event-driven/claude-event-processor.ts
import { Kafka, Consumer, Producer, EachMessagePayload } from 'kafkajs';
import { Anthropic } from '@anthropic-ai/sdk';
import { EventStore } from './event-store';
 
interface ClaudeEvent {
  id: string;
  type: string;
  aggregateId: string;
  data: any;
  metadata: {
    userId: string;
    timestamp: string;
    version: number;
  };
}
 
export class ClaudeEventProcessor {
  private kafka: Kafka;
  private consumer: Consumer;
  private producer: Producer;
  private anthropic: Anthropic;
  private eventStore: EventStore;
  
  constructor() {
    this.kafka = new Kafka({
      clientId: 'claude-event-processor',
      brokers: ['kafka:9092']
    });
    
    this.consumer = this.kafka.consumer({ 
      groupId: 'claude-processing-group' 
    });
    this.producer = this.kafka.producer();
    this.anthropic = new Anthropic();
    this.eventStore = new EventStore();
  }
  
  async start() {
    await this.consumer.connect();
    await this.producer.connect();
    
    // Subscribe to topics
    await this.consumer.subscribe({ 
      topics: [
        'claude.requests',
        'claude.commands',
        'system.events'
      ],
      fromBeginning: false 
    });
    
    // Process events
    await this.consumer.run({
      eachMessage: this.handleMessage.bind(this)
    });
  }
  
  private async handleMessage({ topic, partition, message }: EachMessagePayload) {
    const event: ClaudeEvent = JSON.parse(message.value.toString());
    
    try {
      // Store event
      await this.eventStore.append(event);
      
      // Route based on event type
      switch (event.type) {
        case 'PromptRequested':
          await this.handlePromptRequest(event);
          break;
          
        case 'AnalysisRequested':
          await this.handleAnalysisRequest(event);
          break;
          
        case 'BatchProcessingRequested':
          await this.handleBatchRequest(event);
          break;
          
        case 'SystemMetricReceived':
          await this.handleSystemMetric(event);
          break;
      }
      
      // Acknowledge processing
      await this.consumer.commitOffsets([{
        topic,
        partition,
        offset: (parseInt(message.offset) + 1).toString()
      }]);
      
    } catch (error) {
      // Send to error topic
      await this.producer.send({
        topic: 'claude.errors',
        messages: [{
          key: event.id,
          value: JSON.stringify({
            originalEvent: event,
            error: error.message,
            timestamp: new Date().toISOString()
          })
        }]
      });
    }
  }
  
  private async handlePromptRequest(event: ClaudeEvent) {
    const { prompt, model, options } = event.data;
    
    // Process with Claude
    const response = await this.anthropic.messages.create({
      messages: [{ role: 'user', content: prompt }],
      model: model || 'claude-3-sonnet-20240229',
      ...options
    });
    
    // Publish response event
    await this.publishEvent({
      type: 'PromptCompleted',
      aggregateId: event.aggregateId,
      data: {
        requestId: event.id,
        response: response.content[0].text,
        usage: response.usage
      },
      metadata: {
        ...event.metadata,
        processingTime: Date.now() - new Date(event.metadata.timestamp).getTime()
      }
    });
  }
  
  private async handleAnalysisRequest(event: ClaudeEvent) {
    const { documents, analysisType } = event.data;
    
    // Prepare analysis prompt
    const prompt = this.buildAnalysisPrompt(documents, analysisType);
    
    // Get analysis from Claude
    const response = await this.anthropic.messages.create({
      messages: [{ role: 'user', content: prompt }],
      model: 'claude-3-opus-20240229', // Use more capable model
      max_tokens: 4000
    });
    
    // Extract structured data
    const analysis = this.parseAnalysisResponse(response.content[0].text);
    
    // Publish analysis completed event
    await this.publishEvent({
      type: 'AnalysisCompleted',
      aggregateId: event.aggregateId,
      data: {
        requestId: event.id,
        analysis,
        confidence: analysis.confidence,
        recommendations: analysis.recommendations
      },
      metadata: event.metadata
    });
    
    // Trigger follow-up actions
    if (analysis.requiresAction) {
      await this.publishEvent({
        type: 'ActionRequired',
        aggregateId: event.aggregateId,
        data: {
          analysisId: event.id,
          actions: analysis.suggestedActions
        },
        metadata: event.metadata
      });
    }
  }
  
  private async publishEvent(event: Partial<ClaudeEvent>) {
    const fullEvent: ClaudeEvent = {
      id: this.generateEventId(),
      ...event,
      metadata: {
        ...event.metadata,
        timestamp: new Date().toISOString()
      }
    };
    
    await this.producer.send({
      topic: `claude.${event.type.toLowerCase()}`,
      messages: [{
        key: fullEvent.aggregateId,
        value: JSON.stringify(fullEvent),
        headers: {
          eventType: event.type,
          version: '1.0'
        }
      }]
    });
  }
  
  // Event Sourcing with Projections
  async rebuildProjection(aggregateId: string, toVersion?: number) {
    const events = await this.eventStore.getEvents(aggregateId, toVersion);
    
    const projection = events.reduce((state, event) => {
      return this.applyEvent(state, event);
    }, {});
    
    return projection;
  }
  
  private applyEvent(state: any, event: ClaudeEvent): any {
    switch (event.type) {
      case 'PromptRequested':
        return {
          ...state,
          prompts: [...(state.prompts || []), event.data]
        };
        
      case 'PromptCompleted':
        return {
          ...state,
          responses: [...(state.responses || []), event.data]
        };
        
      default:
        return state;
    }
  }
}

Event Orchestration with Temporal

// orchestration/claude-temporal-workflow.ts
import { proxyActivities, sleep } from '@temporalio/workflow';
import type * as activities from './activities';
 
const { processWithClaude, validateResult, notifyWebhook } = proxyActivities<
  typeof activities
>({
  startToCloseTimeout: '5 minutes',
  retry: {
    initialInterval: '1s',
    backoffCoefficient: 2,
    maximumAttempts: 5
  }
});
 
export async function claudeProcessingWorkflow(input: {
  requestId: string;
  prompt: string;
  webhookUrl: string;
  validationRules: any[];
}): Promise<any> {
  // Step 1: Process with Claude
  const claudeResult = await processWithClaude({
    prompt: input.prompt,
    requestId: input.requestId
  });
  
  // Step 2: Validate result
  const validationResult = await validateResult({
    result: claudeResult,
    rules: input.validationRules
  });
  
  if (!validationResult.isValid) {
    // Retry with modified prompt
    const retryResult = await processWithClaude({
      prompt: `${input.prompt}\n\nPlease address these issues: ${validationResult.errors.join(', ')}`,
      requestId: input.requestId
    });
    
    // Re-validate
    const retryValidation = await validateResult({
      result: retryResult,
      rules: input.validationRules
    });
    
    if (!retryValidation.isValid) {
      throw new Error('Failed validation after retry');
    }
  }
  
  // Step 3: Notify webhook
  await notifyWebhook({
    url: input.webhookUrl,
    data: {
      requestId: input.requestId,
      result: claudeResult,
      status: 'completed'
    }
  });
  
  return {
    requestId: input.requestId,
    result: claudeResult,
    completedAt: new Date().toISOString()
  };
}
 
// Saga pattern for complex workflows
export async function claudeSagaWorkflow(input: {
  orderId: string;
  tasks: Array<{ type: string; data: any }>;
}): Promise<any> {
  const compensations: Array<() => Promise<void>> = [];
  const results: any[] = [];
  
  try {
    for (const task of input.tasks) {
      switch (task.type) {
        case 'analyze':
          const analysis = await processWithClaude({
            prompt: `Analyze: ${JSON.stringify(task.data)}`,
            requestId: `${input.orderId}-analyze`
          });
          results.push(analysis);
          
          // Add compensation
          compensations.push(async () => {
            await notifyWebhook({
              url: task.data.rollbackUrl,
              data: { orderId: input.orderId, action: 'rollback-analysis' }
            });
          });
          break;
          
        case 'generate':
          const generation = await processWithClaude({
            prompt: `Generate: ${JSON.stringify(task.data)}`,
            requestId: `${input.orderId}-generate`
          });
          results.push(generation);
          
          compensations.push(async () => {
            await notifyWebhook({
              url: task.data.rollbackUrl,
              data: { orderId: input.orderId, action: 'rollback-generation' }
            });
          });
          break;
      }
    }
    
    return { orderId: input.orderId, results, status: 'completed' };
    
  } catch (error) {
    // Execute compensations in reverse order
    for (const compensation of compensations.reverse()) {
      await compensation();
    }
    throw error;
  }
}

Best Practices and Recommendations

1. API Design Principles

  • Use appropriate protocols: GraphQL for flexible queries, gRPC for internal services, REST for public APIs
  • Implement versioning: Support multiple API versions simultaneously
  • Design for idempotency: Ensure operations can be safely retried
  • Use consistent error formats: Standardize error responses across all APIs

2. Performance Optimization

  • Implement caching: Cache Claude responses where appropriate
  • Use connection pooling: Maintain persistent connections for better performance
  • Batch requests: Combine multiple small requests into batches
  • Implement circuit breakers: Protect against cascading failures

3. Security Considerations

  • Authenticate all requests: Use JWT tokens or API keys
  • Implement rate limiting: Protect against abuse and ensure fair usage
  • Encrypt sensitive data: Use TLS for all communications
  • Validate inputs: Sanitize and validate all user inputs

4. Monitoring and Observability

  • Implement distributed tracing: Track requests across services
  • Log all API interactions: Maintain audit trails
  • Monitor performance metrics: Track latency, throughput, and error rates
  • Set up alerts: Notify on anomalies or threshold breaches

5. Testing Strategies

  • Unit test all components: Test individual functions and methods
  • Integration testing: Test API endpoints and service interactions
  • Load testing: Ensure system can handle expected traffic
  • Chaos engineering: Test resilience to failures

Conclusion

Advanced API integration patterns enable building robust, scalable AI applications with Claude Code. By combining GraphQL’s flexibility, WebSocket’s real-time capabilities, gRPC’s performance, and event-driven architectures, developers can create sophisticated systems that leverage Claude’s capabilities effectively.

Key takeaways:

  • Choose the right protocol for each use case
  • Implement proper rate limiting and quota management
  • Design for resilience with circuit breakers and retries
  • Use event-driven architectures for scalability
  • Monitor and observe all API interactions

External References


Last Updated: 2025-07-22 Status: Experimental - Patterns and implementations are subject to change