# api-design > Guidelines for designing RESTful APIs and TypeScript interfaces. Use when designing new endpoints, reviewing API contracts, or structuring data models. - Author: jonnyamsp - Repository: Agentz360/secure-mastra - Version: 20260210040322 - Stars: 0 - Forks: 0 - Last Updated: 2026-02-10 - Source: https://github.com/Agentz360/secure-mastra - Web: https://mule.run/skillshub/@@Agentz360/secure-mastra~api-design:20260210040322 --- --- name: api-design description: Guidelines for designing RESTful APIs and TypeScript interfaces. Use when designing new endpoints, reviewing API contracts, or structuring data models. license: MIT --- # API Design Guidelines ## Overview This skill provides guidelines for designing clean, consistent APIs. Apply these patterns when creating new endpoints, defining TypeScript interfaces, or reviewing API contracts. **Keywords**: API design, REST, endpoints, TypeScript interfaces, data modeling, HTTP methods, response formats ## REST Endpoint Design ### URL Structure ``` /{resource} # Collection /{resource}/{id} # Single resource /{resource}/{id}/{sub-resource} # Nested resource ``` **Good examples:** - `GET /users` - List users - `GET /users/123` - Get user 123 - `POST /users/123/orders` - Create order for user 123 **Avoid:** - `/getUsers` - Don't use verbs in URLs - `/user/list` - Don't use action words - `/users/123/getOrders` - HTTP method implies action ### HTTP Methods | Method | Purpose | Idempotent | Body | | ------ | ---------------- | ---------- | ---- | | GET | Read resource | Yes | No | | POST | Create resource | No | Yes | | PUT | Replace resource | Yes | Yes | | PATCH | Update resource | No | Yes | | DELETE | Remove resource | Yes | No | ### Response Codes **Success:** - `200` - OK (GET, PUT, PATCH with body) - `201` - Created (POST) - `204` - No Content (DELETE, PUT/PATCH without body) **Client errors:** - `400` - Bad Request (validation failed) - `401` - Unauthorized (no/invalid auth) - `403` - Forbidden (no permission) - `404` - Not Found - `409` - Conflict (duplicate, state conflict) - `422` - Unprocessable Entity (semantic errors) **Server errors:** - `500` - Internal Server Error - `503` - Service Unavailable ## Response Formats ### Success Response ```typescript // Single resource { "data": { "id": "123", "name": "Example", "createdAt": "2024-01-15T10:30:00Z" } } // Collection { "data": [...], "meta": { "total": 100, "page": 1, "pageSize": 20 } } ``` ### Error Response ```typescript { "error": { "code": "VALIDATION_ERROR", "message": "Request validation failed", "details": [ { "field": "email", "message": "Invalid email format" } ] } } ``` ## TypeScript Interface Design ### Naming Conventions ```typescript // Entities use PascalCase nouns interface User {} interface OrderItem {} // Request/Response types include suffix interface CreateUserRequest {} interface GetUserResponse {} // Params types for function arguments interface ListUsersParams {} ``` ### Required vs Optional ```typescript // Required fields: always present interface User { id: string; email: string; createdAt: Date; } // Optional fields: may be undefined interface CreateUserRequest { email: string; name?: string; // Optional metadata?: Record; } ``` ### Discriminated Unions Use for type-safe variants: ```typescript type PaymentMethod = | { type: 'card'; cardNumber: string; expiry: string } | { type: 'bank'; accountNumber: string; routingNumber: string } | { type: 'crypto'; walletAddress: string }; // Usage function processPayment(method: PaymentMethod) { switch (method.type) { case 'card': // TypeScript knows cardNumber exists return chargeCard(method.cardNumber); case 'bank': return initiateTransfer(method.accountNumber); case 'crypto': return sendCrypto(method.walletAddress); } } ``` ## Pagination ### Offset-based (Simple) ```typescript interface PaginationParams { page?: number; // Default: 1 pageSize?: number; // Default: 20, max: 100 } interface PaginatedResponse { data: T[]; meta: { page: number; pageSize: number; total: number; totalPages: number; }; } ``` ### Cursor-based (Scalable) ```typescript interface CursorParams { cursor?: string; limit?: number; } interface CursorResponse { data: T[]; meta: { nextCursor: string | null; hasMore: boolean; }; } ``` ## Versioning ### URL Versioning (Recommended) ``` /api/v1/users /api/v2/users ``` ### Header Versioning ``` Accept: application/vnd.api+json; version=2 ``` ## Common Patterns ### Filtering ``` GET /users?status=active&role=admin GET /orders?createdAfter=2024-01-01&createdBefore=2024-02-01 ``` ### Sorting ``` GET /users?sort=createdAt:desc GET /users?sort=lastName:asc,firstName:asc ``` ### Field Selection ``` GET /users?fields=id,name,email GET /users/123?include=orders,profile ``` ## Security Considerations 1. **Authentication** - Use Bearer tokens in Authorization header 2. **Rate limiting** - Include `X-RateLimit-*` headers 3. **Input validation** - Validate all request bodies with schemas 4. **Output encoding** - Escape HTML in responses if rendered 5. **CORS** - Configure allowed origins explicitly