--- name: sdk-design-patterns description: "SDK/API client design patterns: builder pattern, interceptor chain, retry strategy, type-safe design, error handling, and pagination wrapper guide. Use this skill for requests involving 'SDK design', 'client patterns', 'retry strategy', 'interceptor', 'builder pattern', 'SDK error handling', 'type safety', 'SDK architecture', etc. Enhances sdk-developer's SDK design capabilities. Note: API spec parsing, test authoring, and documentation are outside the scope of this skill." --- # SDK Design Patterns — SDK Design Patterns Guide A pattern catalog for designing type-safe, developer-friendly API client SDKs. ## SDK Architecture ``` +------------------------------------------+ | SDK Public API | | client.users.list() | | client.orders.create({...}) | +------------------------------------------+ | Resource Clients | | UsersClient, OrdersClient, ... | +------------------------------------------+ | Middleware Chain | | Auth -> Retry -> RateLimit -> Logger | +------------------------------------------+ | HTTP Transport | | fetch / axios / httpx | +------------------------------------------+ ``` ## Builder Pattern (Client Initialization) ### TypeScript ```typescript const client = new ApiClient({ baseUrl: 'https://api.example.com', apiKey: process.env.API_KEY, timeout: 30000, retries: 3, // Optional customization fetch: customFetch, headers: { 'X-Custom': 'value' }, }); // Resource access const users = await client.users.list({ page: 1, perPage: 20 }); const user = await client.users.get('user_123'); const newUser = await client.users.create({ name: 'John Doe', email: 'john@test.com' }); ``` ### Python ```python client = ApiClient( base_url="https://api.example.com", api_key=os.environ["API_KEY"], timeout=30.0, max_retries=3, ) # Context manager support async with ApiClient(api_key="...") as client: users = await client.users.list(page=1, per_page=20) ``` ## Interceptor / Middleware Chain ```typescript // Interceptor interface interface Interceptor { beforeRequest(config: RequestConfig): Promise; afterResponse(response: Response): Promise; onError(error: Error): Promise; } // Authentication interceptor class AuthInterceptor implements Interceptor { async beforeRequest(config) { config.headers['Authorization'] = `Bearer ${this.token}`; return config; } async onError(error) { if (error.status === 401 && this.refreshToken) { await this.refresh(); return this.retry(error.config); } throw error; } } // Retry interceptor class RetryInterceptor implements Interceptor { async onError(error) { if (this.shouldRetry(error) && this.attempt < this.maxRetries) { await this.backoff(this.attempt); return this.retry(error.config); } throw error; } } ``` ## Retry Strategy ```typescript class RetryStrategy { private maxRetries = 3; private baseDelay = 1000; // ms shouldRetry(error: ApiError): boolean { // Only retry on retryable errors return [408, 429, 500, 502, 503, 504].includes(error.status); } getDelay(attempt: number, error: ApiError): number { // 429: Retry-After header takes priority if (error.status === 429 && error.headers['retry-after']) { return parseInt(error.headers['retry-after']) * 1000; } // Exponential backoff + jitter const exponential = this.baseDelay * Math.pow(2, attempt); const jitter = Math.random() * this.baseDelay; return Math.min(exponential + jitter, 60000); // Max 60 seconds } } ``` ## Type-Safe Design ### TypeScript Generic Usage ```typescript // Resource type definitions interface User { id: string; name: string; email: string; createdAt: Date; } interface CreateUserRequest { name: string; email: string; } interface ListUsersParams { page?: number; perPage?: number; sort?: 'name' | 'createdAt'; order?: 'asc' | 'desc'; } // Generic resource client class ResourceClient { async list(params?: ListParams): Promise> { ... } async get(id: string): Promise { ... } async create(data: CreateT): Promise { ... } async update(id: string, data: UpdateT): Promise { ... } async delete(id: string): Promise { ... } } // Concrete client class UsersClient extends ResourceClient { // Additional methods async listOrders(userId: string): Promise { ... } } ``` ### Python Pydantic Models ```python from pydantic import BaseModel, Field from datetime import datetime class User(BaseModel): id: str name: str email: str created_at: datetime = Field(alias="createdAt") class Config: populate_by_name = True class CreateUserRequest(BaseModel): name: str email: str ``` ## Pagination Wrapper ```typescript // Auto page traversal class PaginatedResponse { data: T[]; hasMore: boolean; nextCursor?: string; // Iterator support async *[Symbol.asyncIterator](): AsyncIterator { let response: PaginatedResponse = this; while (true) { for (const item of response.data) { yield item; } if (!response.hasMore) break; response = await this.fetchNext(response.nextCursor); } } } // Usage for await (const user of client.users.list()) { console.log(user.name); // Auto-traverses all pages } // Specific page only const page1 = await client.users.list({ perPage: 20 }); ``` ## Error Handling ```typescript // Error class hierarchy class ApiError extends Error { status: number; code: string; details?: any; } class BadRequestError extends ApiError { status = 400; } class AuthenticationError extends ApiError { status = 401; } class NotFoundError extends ApiError { status = 404; } class RateLimitError extends ApiError { status = 429; retryAfter: number; } class InternalError extends ApiError { status = 500; } // Usage try { const user = await client.users.get('invalid_id'); } catch (e) { if (e instanceof NotFoundError) { console.log('User not found'); } else if (e instanceof RateLimitError) { console.log(`Retry after ${e.retryAfter} seconds`); } } ``` ## SDK Quality Checklist ```markdown ### Usability - [ ] Can get started in 3 lines or fewer (Quick Start) - [ ] 100% IDE autocomplete support (fully typed) - [ ] Error messages guide toward resolution - [ ] Supports both sync and async ### Robustness - [ ] Retry + exponential backoff - [ ] Auto token refresh - [ ] Auto rate limit wait - [ ] Configurable timeouts - [ ] Custom HTTP client injection supported ### Testing - [ ] Unit tests for all public APIs - [ ] Mock server integration tests - [ ] Error scenario tests - [ ] Pagination tests ```