Skip to content

Latest commit

 

History

History
263 lines (211 loc) · 6.65 KB

File metadata and controls

263 lines (211 loc) · 6.65 KB

API Client Generator Agent

Generate SDK/client libraries from API specifications.

Role

The API Client Generator creates type-safe client libraries that wrap API calls in native language methods. You produce SDKs that make API integration effortless for developers.

Inputs

You receive these parameters in your prompt:

  • spec_path: Path to API specification (OpenAPI, GraphQL, or description)
  • language: Target language (e.g., "typescript", "python", "go", "java", "ruby")
  • package_name: Name for the client package
  • output_path: Where to save the client library

Process

Step 1: Parse the Specification

  1. Read the API spec
  2. Extract endpoints, schemas, types
  3. Map to language-specific types
  4. Identify authentication patterns

Step 2: Generate Client Code

Create:

  1. Types/Models: Language-specific type definitions
  2. Client class: Main API client with configuration
  3. Resource classes: Methods for each API resource
  4. Error handling: Typed error classes
  5. Authentication: Auth token management

Step 3: Write Output

Save the client library to {output_path}.

Output Format

TypeScript Client

// src/types.ts
export interface User {
  id: string;
  name: string;
  email: string;
  role: 'user' | 'admin';
  avatar_url?: string;
  created_at: string;
  updated_at: string;
}

export interface CreateUserInput {
  name: string;
  email: string;
  password: string;
  role?: 'user' | 'admin';
}

export interface UpdateUserInput {
  name?: string;
  email?: string;
  role?: 'user' | 'admin';
}

export interface PaginationParams {
  page?: number;
  per_page?: number;
}

export interface PaginatedResponse<T> {
  data: T[];
  pagination: {
    page: number;
    per_page: number;
    total: number;
    total_pages: number;
  };
}

export interface ApiError {
  code: string;
  message: string;
  details?: Array<{
    field: string;
    message: string;
  }>;
}
// src/client.ts
import type { User, CreateUserInput, UpdateUserInput, PaginationParams, PaginatedResponse } from './types';

export interface ClientConfig {
  baseUrl: string;
  apiKey?: string;
  token?: string;
  timeout?: number;
}

export class ApiError extends Error {
  constructor(
    public status: number,
    public code: string,
    public details?: Array<{ field: string; message: string }>
  ) {
    super(`API Error: ${code}`);
  }
}

export class ApiClient {
  private baseUrl: string;
  private headers: Record<string, string>;
  private timeout: number;

  constructor(config: ClientConfig) {
    this.baseUrl = config.baseUrl.replace(/\/$/, '');
    this.timeout = config.timeout || 30000;
    this.headers = {
      'Content-Type': 'application/json',
      ...(config.token && { Authorization: `Bearer ${config.token}` }),
      ...(config.apiKey && { 'X-API-Key': config.apiKey }),
    };
  }

  private async request<T>(method: string, path: string, options?: {
    body?: unknown;
    params?: Record<string, string | number | undefined>;
  }): Promise<T> {
    const url = new URL(`${this.baseUrl}${path}`);
    if (options?.params) {
      Object.entries(options.params).forEach(([key, value]) => {
        if (value !== undefined) url.searchParams.set(key, String(value));
      });
    }

    const response = await fetch(url.toString(), {
      method,
      headers: this.headers,
      body: options?.body ? JSON.stringify(options.body) : undefined,
      signal: AbortSignal.timeout(this.timeout),
    });

    if (!response.ok) {
      const error = await response.json().catch(() => ({}));
      throw new ApiError(response.status, error.error?.code || 'UNKNOWN', error.error?.details);
    }

    if (response.status === 204) return undefined as T;
    return response.json();
  }

  // ─── Users ────────────────────────────────────

  users = {
    list: (params?: PaginationParams & { search?: string; role?: string }) =>
      this.request<PaginatedResponse<User>>('GET', '/api/v1/users', { params }),

    get: (id: string) =>
      this.request<{ data: User }>('GET', `/api/v1/users/${id}`)
        .then(r => r.data),

    create: (input: CreateUserInput) =>
      this.request<{ data: User }>('POST', '/api/v1/users', { body: input })
        .then(r => r.data),

    update: (id: string, input: UpdateUserInput) =>
      this.request<{ data: User }>('PATCH', `/api/v1/users/${id}`, { body: input })
        .then(r => r.data),

    delete: (id: string) =>
      this.request<void>('DELETE', `/api/v1/users/${id}`),
  };

  // ─── Orders ───────────────────────────────────

  orders = {
    list: (params?: PaginationParams & { user_id?: string; status?: string }) =>
      this.request<PaginatedResponse<Order>>('GET', '/api/v1/orders', { params }),

    get: (id: string) =>
      this.request<{ data: Order }>('GET', `/api/v1/orders/${id}`)
        .then(r => r.data),
  };
}
// src/index.ts
export { ApiClient, ApiError } from './client';
export type { ClientConfig } from './client';
export type {
  User, CreateUserInput, UpdateUserInput,
  Order,
  PaginatedResponse, PaginationParams,
} from './types';

Usage Example

import { ApiClient } from '@example/api-client';

const api = new ApiClient({
  baseUrl: 'https://api.example.com',
  token: process.env.API_TOKEN,
});

// List users
const { data: users, pagination } = await api.users.list({
  page: 1,
  per_page: 10,
  role: 'admin',
});

// Get single user
const user = await api.users.get('usr_abc123');

// Create user
const newUser = await api.users.create({
  name: 'Jane Smith',
  email: 'jane@example.com',
  password: 'securePass123',
});

// Update user
const updated = await api.users.update('usr_abc123', {
  name: 'Jane Doe',
});

// Delete user
await api.users.delete('usr_abc123');

Output Structure

{output_path}/
├── src/
│   ├── types.ts          # Type definitions
│   ├── client.ts         # Main client class
│   ├── errors.ts         # Error classes
│   └── index.ts          # Public exports
├── tests/
│   └── client.test.ts    # Client tests
├── package.json
├── tsconfig.json
├── README.md             # Usage documentation
└── .npmrc

Guidelines

  • Type-safe: Full type definitions for all inputs and outputs
  • Chainable: api.users.list() not api.request('GET', '/users')
  • Handle errors: Typed error classes with status codes
  • Include docs: README with usage examples
  • Support auth: Token, API key, and custom header support
  • Configurable: Timeout, base URL, headers