Claude
Skills
Sign in
Back

api-integration-builder

Included with Lifetime
$97 forever

Generates production-ready API clients with TypeScript types, retry logic, rate limiting, authentication (OAuth, API keys), error handling, and mock responses. Use when user says "integrate API", "API client", "connect to service", or requests third-party service integration.

Backend & APIs

What this skill does


# API Integration Builder

## Purpose

Generates complete, production-ready API clients with all the boilerplate handled: TypeScript types, authentication, retry logic, rate limiting, and error handling.

**For ADHD users**: Instant integration - no need to read API docs and implement everything manually.
**For all users**: Saves hours of boilerplate code, type-safe, production-ready from day one.

## Activation Triggers

- User says: "integrate API", "API client", "connect to service", "create SDK"
- Requests for: Stripe integration, SendGrid, Twilio, any third-party API
- "Set up OAuth" or "implement API authentication"

## Core Workflow

### 1. Gather Requirements

Ask user for:
```javascript
{
  api_name: "Stripe",
  api_base_url: "https://api.stripe.com/v1",
  auth_type: "api_key|oauth|bearer|basic",
  endpoints: [
    { method: "GET", path: "/customers", description: "List customers" },
    { method: "POST", path: "/customers", description: "Create customer" }
  ],
  rate_limit: { requests: 100, per: "minute" } // optional
}
```

**If user provides API documentation URL**, fetch it and extract this information automatically.

### 2. Generate TypeScript Client

**File structure**:
```
api-client/
├── client.ts              # Main client class
├── types.ts               # TypeScript types
├── auth.ts                # Authentication handler
├── errors.ts              # Custom error classes
├── retry.ts               # Retry logic
├── rate-limiter.ts        # Rate limiting
└── mocks.ts               # Mock responses for testing
```

### 3. Client Template

```typescript
// client.ts
import axios, { AxiosInstance, AxiosRequestConfig } from 'axios';
import { AuthHandler } from './auth';
import { RateLimiter } from './rate-limiter';
import { RetryHandler } from './retry';
import { APIError, RateLimitError, AuthenticationError } from './errors';
import type { ClientConfig, APIResponse } from './types';

export class {APIName}Client {
  private axios: AxiosInstance;
  private auth: AuthHandler;
  private rateLimiter: RateLimiter;
  private retryHandler: RetryHandler;

  constructor(config: ClientConfig) {
    this.auth = new AuthHandler(config.apiKey);
    this.rateLimiter = new RateLimiter(config.rateLimit);
    this.retryHandler = new RetryHandler(config.retryConfig);

    this.axios = axios.create({
      baseURL: config.baseURL,
      timeout: config.timeout || 30000,
      headers: {
        'Content-Type': 'application/json',
        'User-Agent': '{APIName}-Client/1.0.0',
        ...config.defaultHeaders,
      },
    });

    // Request interceptor for auth
    this.axios.interceptors.request.use(
      async (config) => {
        await this.rateLimiter.wait();
        return this.auth.addAuthHeaders(config);
      },
      (error) => Promise.reject(error)
    );

    // Response interceptor for retry logic
    this.axios.interceptors.response.use(
      (response) => response,
      async (error) => {
        if (this.retryHandler.shouldRetry(error)) {
          return this.retryHandler.retry(error);
        }
        return Promise.reject(this.handleError(error));
      }
    );
  }

  private handleError(error: any): Error {
    if (error.response?.status === 401) {
      return new AuthenticationError('Invalid API credentials');
    }
    if (error.response?.status === 429) {
      return new RateLimitError('Rate limit exceeded');
    }
    if (error.response?.data?.message) {
      return new APIError(error.response.data.message, error.response.status);
    }
    return new APIError('Unknown API error', error.response?.status);
  }

  // Generated methods for each endpoint
  async listCustomers(params?: ListCustomersParams): Promise<APIResponse<Customer[]>> {
    const response = await this.axios.get('/customers', { params });
    return response.data;
  }

  async createCustomer(data: CreateCustomerData): Promise<APIResponse<Customer>> {
    const response = await this.axios.post('/customers', data);
    return response.data;
  }

  // ... more generated methods
}
```

### 4. Authentication Handler

```typescript
// auth.ts
import { AxiosRequestConfig } from 'axios';

export type AuthConfig =
  | { type: 'api_key'; key: string; header?: string }
  | { type: 'bearer'; token: string }
  | { type: 'oauth'; clientId: string; clientSecret: string; tokenUrl: string }
  | { type: 'basic'; username: string; password: string };

export class AuthHandler {
  private config: AuthConfig;
  private accessToken?: string;
  private tokenExpiry?: Date;

  constructor(config: AuthConfig) {
    this.config = config;
  }

  async addAuthHeaders(axiosConfig: AxiosRequestConfig): Promise<AxiosRequestConfig> {
    const headers = axiosConfig.headers || {};

    switch (this.config.type) {
      case 'api_key':
        headers[this.config.header || 'Authorization'] = `Bearer ${this.config.key}`;
        break;

      case 'bearer':
        headers['Authorization'] = `Bearer ${this.config.token}`;
        break;

      case 'oauth':
        const token = await this.getOAuthToken();
        headers['Authorization'] = `Bearer ${token}`;
        break;

      case 'basic':
        const credentials = Buffer.from(
          `${this.config.username}:${this.config.password}`
        ).toString('base64');
        headers['Authorization'] = `Basic ${credentials}`;
        break;
    }

    return { ...axiosConfig, headers };
  }

  private async getOAuthToken(): Promise<string> {
    // Check if token is still valid
    if (this.accessToken && this.tokenExpiry && this.tokenExpiry > new Date()) {
      return this.accessToken;
    }

    // Fetch new token
    const response = await axios.post(this.config.tokenUrl, {
      grant_type: 'client_credentials',
      client_id: this.config.clientId,
      client_secret: this.config.clientSecret,
    });

    this.accessToken = response.data.access_token;
    this.tokenExpiry = new Date(Date.now() + response.data.expires_in * 1000);

    return this.accessToken;
  }
}
```

### 5. Retry Logic

```typescript
// retry.ts
import { AxiosError, AxiosRequestConfig } from 'axios';

export interface RetryConfig {
  maxRetries: number;
  initialDelay: number; // ms
  maxDelay: number; // ms
  backoffFactor: number;
  retryableStatuses: number[];
}

export class RetryHandler {
  private config: RetryConfig;
  private retryCount: Map<string, number> = new Map();

  constructor(config?: Partial<RetryConfig>) {
    this.config = {
      maxRetries: config?.maxRetries || 3,
      initialDelay: config?.initialDelay || 1000,
      maxDelay: config?.maxDelay || 30000,
      backoffFactor: config?.backoffFactor || 2,
      retryableStatuses: config?.retryableStatuses || [408, 429, 500, 502, 503, 504],
    };
  }

  shouldRetry(error: AxiosError): boolean {
    if (!error.response) return true; // Network error, retry
    if (!this.config.retryableStatuses.includes(error.response.status)) return false;

    const key = this.getRequestKey(error.config);
    const count = this.retryCount.get(key) || 0;

    return count < this.config.maxRetries;
  }

  async retry(error: AxiosError): Promise<any> {
    const key = this.getRequestKey(error.config);
    const count = this.retryCount.get(key) || 0;

    this.retryCount.set(key, count + 1);

    const delay = Math.min(
      this.config.initialDelay * Math.pow(this.config.backoffFactor, count),
      this.config.maxDelay
    );

    await this.sleep(delay);

    return axios.request(error.config);
  }

  private getRequestKey(config: AxiosRequestConfig): string {
    return `${config.method}:${config.url}`;
  }

  private sleep(ms: number): Promise<void> {
    return new Promise((resolve) => setTimeout(resolve, ms));
  }
}
```

### 6. Rate Limiter

```typescript
// rate-limiter.ts
export interface RateLimitConfig {
  requests: number;
  per: 'second' | 'minute' | 'hour';
}

export class RateLimiter {
  private config: RateLimitConfig;
  private timestamps: number[] = [];

  constructor(config: RateLi

Related in Backend & APIs