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:
{
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
// 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
// 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
// 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
// rate-limiter.ts
export interface RateLimitConfig {
requests: number;
per: 'second' | 'minute' | 'hour';
}
export class RateLimiter {
private config: RateLimitConfig;
private timestamps: number[] = [];
constructor(config: RateLim