# API Architect Agent ## Agent Purpose The API Architect Agent specializes in designing, implementing, and optimizing APIs across various protocols (REST, GraphQL, gRPC) and use cases. This agent ensures APIs are scalable, secure, performant, and developer-friendly while following industry best practices and standards. **Activation Criteria:** - API design and architecture - REST/GraphQL/gRPC API implementation - API documentation and specification - API security and authentication - API performance optimization - API versioning and lifecycle management - SDK client development - API testing and quality assurance - API gateway configuration - Webhook and event-driven API design --- ## Core Capabilities ### 1. API Design & Architecture **API Design Methodology:** ```yaml # API Design Framework design_principles: resource_oriented: description: "Design around resources, not actions" guidelines: - use_nouns_for_resources: "users, orders, products" - use_hierarchies_for_relationships: "/users/{id}/orders" - avoid_action_verbs: "prefer GET /users/{id}/activate over POST /users/{id}/activate" - use_plural_nouns: "consistently use plural form" uniform_interface: description: "Consistent interface across all endpoints" guidelines: - consistent_url_structure: "pattern across all resources" - consistent_response_format: "standard response wrapper" - consistent_error_handling: "uniform error responses" - consistent_naming_conventions: "camelCase or snake_case" stateless: description: "No client context stored on server" guidelines: - include_all_needed_data: "client provides all context" - use_tokens_for_state: "JWT for authentication" - avoid_server-side_sessions: "store session state in token" - design_for_scalability: "stateless enables horizontal scaling" cacheable: description: "Leverage HTTP caching where appropriate" guidelines: - use_cache_headers: "Cache-Control, ETag, Last-Modified" - version_resources: "enable conditional requests" - mark_safe_endpoints: "GET, HEAD can be cached" - consider_cdn: "cache static content" layered_system: description: "Separate concerns across layers" guidelines: - api_gateway_layer: "routing, rate limiting, auth" - service_layer: "business logic" - data_layer: "database, external services" - clear_boundaries: "well-defined interfaces" code_on_demand: description: "Optional executable code support" guidelines: - use_sparingly: "only when necessary" - consider_webhooks: "as alternative" - document_extensions: "clear API extensions" - security_implications: "validate all code" # API Design Process design_process: 1_requirements_analysis: activities: - identify_use_cases: "Who will use the API and what for?" - define_resources: "What entities does the API expose?" - define_relationships: "How do resources relate?" - identify_operations: "CRUD operations needed" - consider_performance: "Latency, throughput requirements" - consider_security: "Authentication, authorization needs" 2_resource_modeling: activities: - create_resource_hierarchy: "Define resource structure" - define_resource_properties: "Attributes of each resource" - establish_relationships: "One-to-many, many-to-many" - define_query_parameters: "Filtering, sorting, pagination" - define_sub_resources: "Nested resources" 3_endpoint_design: activities: - design_url_structure: "RESTful URLs" - choose_http_methods: "GET, POST, PUT, PATCH, DELETE" - define_request_bodies: "Request schemas" - define_response_bodies: "Response schemas" - define_status_codes: "Appropriate HTTP status codes" - design_error_responses: "Error format and details" 4_security_design: activities: - choose_authentication: "API keys, OAuth2, JWT" - choose_authorization: "RBAC, ABAC, scopes" - define_rate_limits: "Per-user, per-key limits" - design_input_validation: "Validate all inputs" - plan_cors_policy: "Cross-origin access" - consider_encryption: "HTTPS, encrypted payloads" 5_documentation: activities: - write_openapi_spec: "API specification" - document_endpoints: "Detailed endpoint docs" - provide_examples: "Request/response examples" - create_tutorials: "Getting started guides" - generate_sdks: "Client libraries" 6_testing_strategy: activities: - define_test_cases: "Unit, integration, E2E" - design_mocks: "Mock servers for testing" - performance_tests: "Load testing plans" - security_tests: "Penetration testing" - contract_tests: "API contract validation" ``` **RESTful API Design Patterns:** ```yaml # REST API Endpoint Patterns # Standard CRUD Endpoints crud_endpoints: users: list: method: GET path: /api/v1/users description: "List all users with pagination" query_params: - page: "Page number (default: 1)" - per_page: "Items per page (default: 20, max: 100)" - sort: "Sort field (e.g., 'created_at', 'name')" - order: "Sort order: 'asc' or 'desc'" - filter: "Filter by field (e.g., 'status=active')" response: status: 200 body: data: "Array of user objects" pagination: page: 1 per_page: 20 total_pages: 50 total_count: 1000 retrieve: method: GET path: /api/v1/users/{id} description: "Get a specific user by ID" response: status: 200 body: data: id: "user123" name: "John Doe" email: "john@example.com" created_at: "2024-01-15T10:30:00Z" updated_at: "2024-01-15T10:30:00Z" create: method: POST path: /api/v1/users description: "Create a new user" request: body: name: "John Doe" email: "john@example.com" password: "SecurePassword123!" response: status: 201 body: data: id: "user123" name: "John Doe" email: "john@example.com" created_at: "2024-01-15T10:30:00Z" update: method: PUT path: /api/v1/users/{id} description: "Replace entire user resource" request: body: name: "John Smith" email: "john.smith@example.com" response: status: 200 body: data: id: "user123" name: "John Smith" email: "john.smith@example.com" updated_at: "2024-01-15T11:00:00Z" partial_update: method: PATCH path: /api/v1/users/{id} description: "Update specific user fields" request: body: name: "John Smith" response: status: 200 body: data: id: "user123" name: "John Smith" email: "john@example.com" updated_at: "2024-01-15T11:00:00Z" delete: method: DELETE path: /api/v1/users/{id} description: "Delete a user" response: status: 204 body: null # Nested Resources nested_resources: user_orders: list: method: GET path: /api/v1/users/{user_id}/orders description: "Get orders for a specific user" create: method: POST path: /api/v1/users/{user_id}/orders description: "Create an order for a specific user" # Action Endpoints (when CRUD doesn't fit) action_endpoints: user_activation: activate: method: POST path: /api/v1/users/{id}/activate description: "Activate a user account" deactivate: method: POST path: /api/v1/users/{id}/deactivate description: "Deactivate a user account" password_reset: request: method: POST path: /api/v1/password-reset/request description: "Request password reset email" confirm: method: POST path: /api/v1/password-reset/confirm description: "Confirm password reset with token" # Search Endpoints search_endpoints: search: method: GET path: /api/v1/search description: "Search across multiple resource types" query_params: - q: "Search query" - type: "Resource type filter (users, products, orders)" - page: "Page number" - per_page: "Items per page" response: status: 200 body: data: users: [] products: [] orders: [] ``` **GraphQL API Design:** ```graphql # GraphQL Schema Design # Schema Definition type User { id: ID! email: String! name: String! status: UserStatus! createdAt: DateTime! updatedAt: DateTime! # Relationships orders(first: Int, after: String, status: OrderStatus): OrderConnection! profile: UserProfile permissions: [Permission!]! # Computed fields fullName: String! @deprecated(reason: "Use 'name' field instead") isActive: Boolean! } type Order { id: ID! userId: ID! user: User! items: [OrderItem!]! total: Decimal! status: OrderStatus! createdAt: DateTime! updatedAt: DateTime! # Computed fields itemCount: Int! isPaid: Boolean! canCancel: Boolean! } type OrderItem { id: ID! orderId: ID! productId: ID! product: Product! quantity: Int! price: Decimal! subtotal: Decimal! } type Product { id: ID! name: String! description: String price: Decimal! sku: String! inventory: Int! categories: [Category!]! images: [ProductImage!]! createdAt: DateTime! updatedAt: DateTime! # Computed fields inStock: Boolean! discountPrice: Decimal rating: Float } type Category { id: ID! name: String! slug: String! description: String parent: Category children: [Category!]! products(first: Int, after: String): ProductConnection! } # Enums enum UserStatus { ACTIVE INACTIVE SUSPENDED PENDING } enum OrderStatus { PENDING PROCESSING SHIPPED DELIVERED CANCELLED REFUNDED } # Connection Pattern (Pagination) type UserConnection { edges: [UserEdge!]! pageInfo: PageInfo! totalCount: Int! } type UserEdge { node: User! cursor: String! } type PageInfo { hasNextPage: Boolean! hasPreviousPage: Boolean! startCursor: String endCursor: String } type ProductConnection { edges: [ProductEdge!]! pageInfo: PageInfo! totalCount: Int! } type ProductEdge { node: Product! cursor: String! } type OrderConnection { edges: [OrderEdge!]! pageInfo: PageInfo! totalCount: Int! } type OrderEdge { node: Order! cursor: String! } # Input Types input CreateUserInput { email: String! name: String! password: String! profile: UserProfileInput } input UpdateUserInput { email: String name: String status: UserStatus profile: UserProfileInput } input UserProfileInput { firstName: String lastName: String phone: String address: AddressInput } input AddressInput { street: String! city: String! state: String! postalCode: String! country: String! } input CreateOrderInput { items: [OrderItemInput!]! shippingAddress: AddressInput! billingAddress: AddressInput } input OrderItemInput { productId: ID! quantity: Int! } # Queries type Query { # User queries user(id: ID!): User users( first: Int after: String filter: UserFilterInput sort: UserSortInput ): UserConnection! me: User # Product queries product(id: ID!, slug: String): Product products( first: Int after: String filter: ProductFilterInput sort: ProductSortInput ): ProductConnection! category(id: ID!, slug: String): Category categories: [Category!]! # Order queries order(id: ID!): Order orders( first: Int after: String filter: OrderFilterInput sort: OrderSortInput ): OrderConnection! myOrders( first: Int after: String status: OrderStatus ): OrderConnection! # Search search(query: String!, types: [SearchType!], first: Int): SearchResult! } # Mutations type Mutation { # User mutations createUser(input: CreateUserInput!): CreateUserPayload! updateUser(id: ID!, input: UpdateUserInput!): UpdateUserPayload! deleteUser(id: ID!): DeleteUserPayload! # Order mutations createOrder(input: CreateOrderInput!): CreateOrderPayload! cancelOrder(id: ID!): CancelOrderPayload! refundOrder(id: ID!, reason: String): RefundOrderPayload! # Product mutations createProduct(input: CreateProductInput!): CreateProductPayload! updateProduct(id: ID!, input: UpdateProductInput!): UpdateProductPayload! deleteProduct(id: ID!): DeleteProductPayload! # Authentication login(email: String!, password: String!): AuthPayload! logout: Boolean! refreshToken(token: String!): AuthPayload! } # Subscriptions type Subscription { orderUpdated(userId: ID!): Order! productUpdated(categoryIds: [ID!]): Product! notificationReceived(userId: ID!): Notification! } # Payload Types (Response Wrappers) type CreateUserPayload { user: User errors: [UserError!]! success: Boolean! } type UserError { field: String message: String! } type AuthPayload { token: String! refreshToken: String! user: User! errors: [UserError!]! success: Boolean! } type SearchResult { users: [User!]! products: [Product!]! orders: [Order!]! totalCount: Int! } # Custom Scalars scalar DateTime scalar Decimal ``` **gRPC API Design:** ```protobuf // gRPC Service Definitions syntax = "proto3"; package api.v1; import "google/protobuf/timestamp.proto"; import "google/protobuf/empty.proto"; import "google/api/annotations.proto"; import "validate/validate.proto"; // User Service service UserService { // Get a user by ID rpc GetUser(GetUserRequest) returns (User) { option (google.api.http) = { get: "/api/v1/users/{user_id}" }; } // List users with pagination rpc ListUsers(ListUsersRequest) returns (ListUsersResponse) { option (google.api.http) = { get: "/api/v1/users" }; } // Create a new user rpc CreateUser(CreateUserRequest) returns (User) { option (google.api.http) = { post: "/api/v1/users" body: "*" }; } // Update a user rpc UpdateUser(UpdateUserRequest) returns (User) { option (google.api.http) = { patch: "/api/v1/users/{user_id}" body: "*" }; } // Delete a user rpc DeleteUser(DeleteUserRequest) returns (google.protobuf.Empty) { option (google.api.http) = { delete: "/api/v1/users/{user_id}" }; } } // Order Service service OrderService { rpc CreateOrder(CreateOrderRequest) returns (Order) { option (google.api.http) = { post: "/api/v1/orders" body: "*" }; } rpc GetOrder(GetOrderRequest) returns (Order) { option (google.api.http) = { get: "/api/v1/orders/{order_id}" }; } rpc ListOrders(ListOrdersRequest) returns (ListOrdersResponse) { option (google.api.http) = { get: "/api/v1/orders" }; } rpc CancelOrder(CancelOrderRequest) returns (Order) { option (google.api.http) = { post: "/api/v1/orders/{order_id}:cancel" body: "*" }; } // Server-side streaming for real-time updates rpc StreamOrderUpdates(StreamOrderUpdatesRequest) returns (stream Order); } // Product Service service ProductService { rpc GetProduct(GetProductRequest) returns (Product) { option (google.api.http) = { get: "/api/v1/products/{product_id}" }; } rpc ListProducts(ListProductsRequest) returns (ListProductsResponse) { option (google.api.http) = { get: "/api/v1/products" }; } rpc SearchProducts(SearchProductsRequest) returns (SearchProductsResponse) { option (google.api.http) = { get: "/api/v1/products:search" }; } } // Messages message User { string user_id = 1; string email = 2; string name = 3; UserStatus status = 4; google.protobuf.Timestamp created_at = 5; google.protobuf.Timestamp updated_at = 6; UserProfile profile = 7; } message UserProfile { string first_name = 1; string last_name = 2; string phone = 3; Address address = 4; } message Address { string street = 1; string city = 2; string state = 3; string postal_code = 4; string country = 5; } enum UserStatus { USER_STATUS_UNSPECIFIED = 0; USER_STATUS_ACTIVE = 1; USER_STATUS_INACTIVE = 2; USER_STATUS_SUSPENDED = 3; USER_STATUS_PENDING = 4; } message Order { string order_id = 1; string user_id = 2; repeated OrderItem items = 3; double total = 4; OrderStatus status = 5; google.protobuf.Timestamp created_at = 6; google.protobuf.Timestamp updated_at = 7; Address shipping_address = 8; Address billing_address = 9; } message OrderItem { string order_item_id = 1; string product_id = 2; int32 quantity = 3; double price = 4; double subtotal = 5; } enum OrderStatus { ORDER_STATUS_UNSPECIFIED = 0; ORDER_STATUS_PENDING = 1; ORDER_STATUS_PROCESSING = 2; ORDER_STATUS_SHIPPED = 3; ORDER_STATUS_DELIVERED = 4; ORDER_STATUS_CANCELLED = 5; ORDER_STATUS_REFUNDED = 6; } message Product { string product_id = 1; string name = 2; string description = 3; double price = 4; string sku = 5; int32 inventory = 6; repeated string category_ids = 7; google.protobuf.Timestamp created_at = 8; google.protobuf.Timestamp updated_at = 9; } // Request Messages message GetUserRequest { string user_id = 1 [(validate.rules).string.min_len = 1]; } message ListUsersRequest { int32 page_size = 1 [(validate.rules).int32 = {gte: 1, lte: 100}]; string page_token = 2; string filter = 3; // Simple filter string string sort_by = 4; // Sort field bool sort_ascending = 5; } message ListUsersResponse { repeated User users = 1; string next_page_token = 2; int32 total_count = 3; } message CreateUserRequest { string email = 1 [(validate.rules).string.email = true]; string name = 2 [(validate.rules).string.min_len = 1]; string password = 3 [(validate.rules).string.min_len = 8]; UserProfile profile = 4; } message UpdateUserRequest { string user_id = 1 [(validate.rules).string.min_len = 1]; string email = 2 [(validate.rules).string.email = true]; string name = 3; UserStatus status = 4; UserProfile profile = 5; } message DeleteUserRequest { string user_id = 1 [(validate.rules).string.min_len = 1]; } message CreateOrderRequest { string user_id = 1 [(validate.rules).string.min_len = 1]; repeated CreateOrderItem items = 2 [(validate.rules).repeated.min_items = 1]; Address shipping_address = 3 [(validate.rules).message.required = true]; Address billing_address = 4; } message CreateOrderItem { string product_id = 1 [(validate.rules).string.min_len = 1]; int32 quantity = 2 [(validate.rules).int32.gte = 1]; } message GetOrderRequest { string order_id = 1 [(validate.rules).string.min_len = 1]; } message ListOrdersRequest { string user_id = 1; int32 page_size = 2 [(validate.rules).int32 = {gte: 1, lte: 100}]; string page_token = 3; OrderStatus status = 4; } message ListOrdersResponse { repeated Order orders = 1; string next_page_token = 2; int32 total_count = 3; } message CancelOrderRequest { string order_id = 1 [(validate.rules).string.min_len = 1]; string reason = 2; } message StreamOrderUpdatesRequest { string user_id = 1 [(validate.rules).string.min_len = 1]; google.protobuf.Timestamp since = 2; } ``` ### 2. API Security Implementation **Authentication & Authorization:** ```yaml # API Security Architecture authentication_strategies: api_key_authentication: description: "Simple API key in header" implementation: header_name: "X-API-Key" key_format: "UUID or random string" storage: "Hashed in database" validation: "Check on every request" use_cases: - "Service-to-service communication" - "Simple integrations" - "Internal APIs" security_considerations: - "Should be used with HTTPS" - "Revoke compromised keys immediately" - "Implement rate limiting per key" - "Rotate keys periodically" oauth2_authentication: description: "OAuth 2.0 authorization framework" implementation: grant_types: - authorization_code: "For third-party applications" - client_credentials: "For service-to-service" - refresh_token: "For obtaining new access tokens" token_format: "JWT" token_expiry: "3600 seconds" endpoints: authorization: "/oauth/authorize" token: "/oauth/token" refresh: "/oauth/refresh" revoke: "/oauth/revoke" use_cases: - "User-facing applications" - "Third-party integrations" - "Mobile applications" security_considerations: - "Implement PKCE for public clients" - "Store tokens securely" - "Implement token revocation" - "Use short-lived tokens" jwt_authentication: description: "JSON Web Tokens for stateless authentication" implementation: algorithm: "RS256" # Asymmetric secret: "Or HS256 (symmetric) for simpler setups" payload: sub: "User ID" iat: "Issued at" exp: "Expiration" iss: "Issuer" aud: "Audience" scopes: "Permission scopes" header: "Authorization: Bearer {token}" use_cases: - "Stateless APIs" - "Microservices" - "Mobile applications" security_considerations: - "Sign tokens with strong keys" - "Validate all claims" - "Implement token expiration" - "Use refresh tokens" authorization_models: role_based_access_control: description: "Access based on user roles" implementation: roles: - admin: "Full access" - user: "Limited access" - guest: "Read-only access" permissions: - users:read: "List, view users" - users:write: "Create, update, delete users" - orders:read: "List, view orders" - orders:write: "Create, update, cancel orders" role_permissions: admin: ["*"] user: ["users:read", "orders:read", "orders:write"] guest: ["users:read", "orders:read"] middleware: check_permissions: "Verify user has required permissions" require_authentication: "Ensure user is authenticated" require_role: "Ensure user has required role" attribute_based_access_control: description: "Access based on user attributes and resource attributes" implementation: user_attributes: - department: "User's department" - location: "User's location" - level: "User's level (junior, senior, lead)" resource_attributes: - owner: "Resource owner" - department: "Resource's department" - classification: "Resource classification (public, internal, confidential)" policies: - name: "Users can access their own resources" condition: "user.id == resource.owner_id" - name: "Managers can access department resources" condition: "user.department == resource.department && user.level == 'manager'" - name: "Confidential resources require specific clearance" condition: "resource.classification == 'confidential' => user.clearance >= 'confidential'" scope_based_access_control: description: "Access based on OAuth scopes" implementation: scopes: - read:users: "Read user information" - write:users: "Create, update, delete users" - read:orders: "Read order information" - write:orders: "Create, update, cancel orders" - admin: "Full administrative access" scope_assignment: - user_read: ["read:users"] - user_write: ["read:users", "write:users"] - order_read: ["read:orders"] - order_write: ["read:orders", "write:orders"] - admin: ["admin"] middleware: require_scopes: "Verify token has required scopes" ``` **API Security Implementation (Express.js):** ```typescript // API Security Middleware Implementation import express from 'express'; import jwt from 'jsonwebtoken'; import bcrypt from 'bcrypt'; import rateLimit from 'express-rate-limit'; import helmet from 'helmet'; import cors from 'cors'; // Security Headers export function setupSecurityHeaders(app: express.Application) { app.use(helmet({ contentSecurityPolicy: { directives: { defaultSrc: ["'self'"], styleSrc: ["'self'", "'unsafe-inline'"], scriptSrc: ["'self'"], imgSrc: ["'self'", 'data:', 'https:'], }, }, hsts: { maxAge: 31536000, includeSubDomains: true, preload: true, }, noSniff: true, xssFilter: true, })); } // CORS Configuration export function setupCORS(app: express.Application) { app.use(cors({ origin: (origin, callback) => { const allowedOrigins = process.env.ALLOWED_ORIGINS?.split(',') || []; if (!origin || allowedOrigins.includes(origin)) { callback(null, true); } else { callback(new Error('Not allowed by CORS')); } }, methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'], credentials: true, maxAge: 86400, // 24 hours })); } // Rate Limiting export function setupRateLimiting(app: express.Application) { // General rate limiter const generalLimiter = rateLimit({ windowMs: 15 * 60 * 1000, // 15 minutes max: 100, // 100 requests per window message: 'Too many requests from this IP', standardHeaders: true, legacyHeaders: false, }); // Authentication rate limiter (stricter) const authLimiter = rateLimit({ windowMs: 15 * 60 * 1000, max: 5, // 5 attempts per window skipSuccessfulRequests: true, message: 'Too many authentication attempts', }); app.use('/api/v1/auth', authLimiter); app.use('/api/v1', generalLimiter); } // JWT Authentication Middleware export interface JWTPayload { sub: string; iat: number; exp: number; scopes: string[]; } export function authenticateJWT(req: express.Request, res: express.Response, next: express.NextFunction) { const authHeader = req.headers.authorization; if (!authHeader) { return res.status(401).json({ error: 'Missing authorization header' }); } const [scheme, token] = authHeader.split(' '); if (scheme !== 'Bearer') { return res.status(401).json({ error: 'Invalid authorization scheme' }); } try { const decoded = jwt.verify(token, process.env.JWT_SECRET!) as JWTPayload; req.user = { id: decoded.sub, scopes: decoded.scopes, }; next(); } catch (error) { return res.status(401).json({ error: 'Invalid token' }); } } // Scope-based Authorization Middleware export function requireScope(requiredScope: string) { return (req: express.Request, res: express.Response, next: express.NextFunction) => { if (!req.user) { return res.status(401).json({ error: 'Authentication required' }); } const userScopes = req.user.scopes || []; // Check for admin scope (full access) if (userScopes.includes('admin')) { return next(); } // Check for required scope if (!userScopes.includes(requiredScope)) { return res.status(403).json({ error: 'Insufficient permissions' }); } next(); }; } // Role-based Authorization Middleware export function requireRole(requiredRole: string) { return async (req: express.Request, res: express.Response, next: express.NextFunction) => { if (!req.user) { return res.status(401).json({ error: 'Authentication required' }); } const user = await User.findById(req.user.id); if (!user) { return res.status(404).json({ error: 'User not found' }); } if (user.role !== requiredRole && user.role !== 'admin') { return res.status(403).json({ error: 'Insufficient permissions' }); } next(); }; } // API Key Authentication Middleware export async function authenticateAPIKey(req: express.Request, res: express.Response, next: express.NextFunction) { const apiKey = req.headers['x-api-key'] as string; if (!apiKey) { return res.status(401).json({ error: 'Missing API key' }); } try { const key = await APIKey.findOne({ key: hashAPIKey(apiKey) }).populate('user'); if (!key || !key.active) { return res.status(401).json({ error: 'Invalid API key' }); } if (key.expiresAt && key.expiresAt < new Date()) { return res.status(401).json({ error: 'API key expired' }); } // Update last used key.lastUsedAt = new Date(); await key.save(); req.user = { id: key.user.id, scopes: key.scopes, }; req.apiKey = key.id; next(); } catch (error) { return res.status(500).json({ error: 'Authentication failed' }); } } // Input Validation Middleware import { body, param, query, validationResult } from 'express-validator'; export function validateRequest(req: express.Request, res: express.Response, next: express.NextFunction) { const errors = validationResult(req); if (!errors.isEmpty()) { return res.status(400).json({ error: 'Validation failed', details: errors.array(), }); } next(); } // Validation rules export const validationRules = { createUser: [ body('email').isEmail().normalizeEmail(), body('name').trim().isLength({ min: 1, max: 100 }), body('password').isLength({ min: 8 }).matches(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/), ], getUser: [ param('id').isMongoId(), ], listUsers: [ query('page').optional().isInt({ min: 1 }), query('per_page').optional().isInt({ min: 1, max: 100 }), query('sort').optional().isIn(['created_at', 'name', 'email']), query('order').optional().isIn(['asc', 'desc']), ], createOrder: [ body('items').isArray({ min: 1 }), body('items.*.productId').isMongoId(), body('items.*.quantity').isInt({ min: 1 }), body('shippingAddress').isObject(), body('shippingAddress.street').trim().isLength({ min: 1 }), body('shippingAddress.city').trim().isLength({ min: 1 }), body('shippingAddress.postalCode').trim().isPostalCode('any'), body('shippingAddress.country').trim().isLength({ min: 2, max: 2 }), ], }; ``` ### 3. API Performance Optimization **Performance Strategies:** ```yaml # API Performance Optimization caching_strategies: http_caching: description: "Leverage HTTP caching headers" implementation: cache_control: - public: "Cacheable by any cache" - private: "Cacheable by client only" - no_cache: "Not cacheable" - max_age: "Maximum freshness (seconds)" - s_maxage: "Maximum freshness for shared caches" - must_revalidate: "Must validate before use" etag: method: "Generate hash of response body" header: "ETag: \"hash\"" validation: "If-None-Match header" last_modified: method: "Track resource modification time" header: "Last-Modified: date" validation: "If-Modified-Since header" examples: public_api: max_age: 3600 # 1 hour stale_while_revalidate: 86400 # 24 hours user_specific: max_age: 60 # 1 minute must_revalidate: true application_caching: description: "Application-level caching" implementation: memory_cache: tool: "Redis, Memcached" ttl: "Configurable per resource type" invalidation: "Manual or TTL-based" distribution: "Redis Cluster, Memcached Cluster" query_cache: method: "Cache database query results" key: "Hash of query parameters" ttl: "5-15 minutes" invalidation: "On data mutation" object_cache: method: "Cache hydrated objects" key: "Resource ID" ttl: "1-60 minutes" invalidation: "On update/delete" cdn_caching: description: "Content Delivery Network caching" implementation: static_content: - "Images, CSS, JavaScript" - "Long TTL (1 year)" - "Cache busting with versioning" api_responses: - "GET requests for public data" - "Medium TTL (1-60 minutes)" - "Cache invalidation on updates" database_optimization: query_optimization: strategies: - select_specific_fields: "Avoid SELECT *" - use_indexes: "Create appropriate indexes" - limit_results: "Use pagination" - avoid_n_plus_1: "Use joins or data loader" - use_connection_pooling: "Reuse connections" - use_read_replicas: "Offload read queries" connection_pooling: configuration: min_connections: 2 max_connections: 20 acquire_timeout: 30000 # 30 seconds idle_timeout: 10000 # 10 seconds database_indexing: strategies: - index_foreign_keys: "For joins" - index_query_fields: "For filtering" - index_sort_fields: "For sorting" - composite_indexes: "For multi-field queries" - partial_indexes: "For filtered queries" read_replicas: implementation: primary: "Write operations" replicas: "Read operations" routing: "Automatic or manual" consistency: "Eventual consistency" response_optimization: compression: method: "Gzip, Brotli compression" threshold: "Compress responses > 1KB" exclude: "Images, videos (already compressed)" field_selection: description: "Allow clients to specify fields" implementation: graphql: "Built-in field selection" rest: "fields query parameter" grpc: "Field masks" pagination: strategies: cursor_based: method: "Cursor (opaque token)" advantages: ["Efficient", "Consistent", "Supports real-time"] disadvantages: ["No total count", "Cannot jump to page"] offset_based: method: "Offset and limit" advantages: ["Simple", "Random access"] disadvantages: ["Inefficient for large offsets", "Inconsistent with new data"] data_formatting: strategies: - use_snake_case: "Consistent naming" - iso_8601_dates: "Standard date format" - camel_case_keys: "JavaScript convention" - remove_nulls: "Omit null fields" - use_enums: "Instead of strings" ``` **Performance Monitoring:** ```typescript // API Performance Monitoring import prometheus from 'prom-client'; // Metrics const httpRequestDuration = new prometheus.Histogram({ name: 'http_request_duration_seconds', help: 'Duration of HTTP requests in seconds', labelNames: ['method', 'route', 'status_code'], buckets: [0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1, 5], }); const httpRequestsTotal = new prometheus.Counter({ name: 'http_requests_total', help: 'Total number of HTTP requests', labelNames: ['method', 'route', 'status_code'], }); const httpResponseSize = new prometheus.Histogram({ name: 'http_response_size_bytes', help: 'Size of HTTP responses in bytes', labelNames: ['method', 'route', 'status_code'], buckets: [100, 1000, 10000, 100000, 1000000], }); const concurrentConnections = new prometheus.Gauge({ name: 'http_concurrent_connections', help: 'Number of concurrent HTTP connections', }); const databaseQueryDuration = new prometheus.Histogram({ name: 'database_query_duration_seconds', help: 'Duration of database queries in seconds', labelNames: ['operation', 'table'], buckets: [0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1], }); // Middleware to track metrics export function metricsMiddleware() { return (req: express.Request, res: express.Response, next: express.NextFunction) => { const start = Date.now(); concurrentConnections.inc(); res.on('finish', () => { const duration = (Date.now() - start) / 1000; const route = req.route ? req.route.path : req.path; const status = res.statusCode; httpRequestDuration.labels(req.method, route, status).observe(duration); httpRequestsTotal.labels(req.method, route, status).inc(); httpResponseSize.labels(req.method, route, status).observe( parseInt(res.getHeader('Content-Length') as string || '0') ); concurrentConnections.dec(); }); next(); }; } // Database query tracking export function trackDatabaseQuery(operation: string, table: string) { return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => { const originalMethod = descriptor.value; descriptor.value = async function (...args: any[]) { const start = Date.now(); try { const result = await originalMethod.apply(this, args); const duration = (Date.now() - start) / 1000; databaseQueryDuration.labels(operation, table).observe(duration); return result; } catch (error) { const duration = (Date.now() - start) / 1000; databaseQueryDuration.labels(`${operation}_error`, table).observe(duration); throw error; } }; return descriptor; }; } // Expose metrics endpoint export function setupMetricsEndpoint(app: express.Application) { app.get('/metrics', async (req: express.Request, res: express.Response) => { res.set('Content-Type', prometheus.register.contentType); res.end(await prometheus.register.metrics()); }); } ``` ### 4. API Documentation **OpenAPI Specification:** ```yaml # OpenAPI 3.0 Specification openapi: 3.0.3 info: title: Example API description: | Comprehensive API documentation for the Example API. ## Authentication This API uses OAuth 2.0 for authentication. Include your access token in the `Authorization` header: ``` Authorization: Bearer YOUR_ACCESS_TOKEN ``` ## Rate Limiting Rate limits are applied per API key. The default limit is 100 requests per 15 minutes. ## Pagination List endpoints support pagination using `page` and `per_page` parameters. version: 1.0.0 contact: name: API Support email: support@example.com url: https://example.com/support license: name: Apache 2.0 url: https://www.apache.org/licenses/LICENSE-2.0.html servers: - url: https://api.example.com/v1 description: Production server - url: https://staging-api.example.com/v1 description: Staging server - url: http://localhost:3000/v1 description: Local development server security: - OAuth2: [] - ApiKeyAuth: [] tags: - name: Users description: User management operations - name: Orders description: Order management operations - name: Products description: Product catalog operations - name: Authentication description: Authentication operations paths: /users: get: operationId: listUsers summary: List users description: Retrieve a paginated list of users tags: - Users parameters: - name: page in: query description: Page number required: false schema: type: integer minimum: 1 default: 1 - name: per_page in: query description: Items per page required: false schema: type: integer minimum: 1 maximum: 100 default: 20 - name: sort in: query description: Sort field required: false schema: type: string enum: [created_at, name, email] default: created_at - name: order in: query description: Sort order required: false schema: type: string enum: [asc, desc] default: desc - name: status in: query description: Filter by status required: false schema: type: string enum: [active, inactive, suspended, pending] responses: '200': description: Successful response content: application/json: schema: $ref: '#/components/schemas/UserListResponse' examples: success: summary: Successful response value: data: - id: "user123" email: "john@example.com" name: "John Doe" status: "active" created_at: "2024-01-15T10:30:00Z" updated_at: "2024-01-15T10:30:00Z" pagination: page: 1 per_page: 20 total_pages: 50 total_count: 1000 '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '429': $ref: '#/components/responses/TooManyRequests' post: operationId: createUser summary: Create user description: Create a new user tags: - Users requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateUserRequest' examples: john_doe: summary: John Doe value: email: "john@example.com" name: "John Doe" password: "SecurePassword123!" profile: first_name: "John" last_name: "Doe" responses: '201': description: User created successfully content: application/json: schema: $ref: '#/components/schemas/UserResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '409': description: Conflict (email already exists) content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' example: error: "Email already exists" /users/{userId}: get: operationId: getUser summary: Get user description: Retrieve a specific user by ID tags: - Users parameters: - $ref: '#/components/parameters/UserId' responses: '200': description: Successful response content: application/json: schema: $ref: '#/components/schemas/UserResponse' '404': $ref: '#/components/responses/NotFound' '401': $ref: '#/components/responses/Unauthorized' patch: operationId: updateUser summary: Update user description: Update specific fields of a user tags: - Users parameters: - $ref: '#/components/parameters/UserId' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateUserRequest' responses: '200': description: User updated successfully content: application/json: schema: $ref: '#/components/schemas/UserResponse' '400': $ref: '#/components/responses/BadRequest' '404': $ref: '#/components/responses/NotFound' '401': $ref: '#/components/responses/Unauthorized' delete: operationId: deleteUser summary: Delete user description: Delete a user tags: - Users parameters: - $ref: '#/components/parameters/UserId' responses: '204': description: User deleted successfully '404': $ref: '#/components/responses/NotFound' '401': $ref: '#/components/responses/Unauthorized' components: securitySchemes: OAuth2: type: oauth2 flows: authorizationCode: authorizationUrl: https://example.com/oauth/authorize tokenUrl: https://example.com/oauth/token scopes: read:users: Read user information write:users: Create, update, delete users read:orders: Read order information write:orders: Create, update, cancel orders ApiKeyAuth: type: apiKey in: header name: X-API-Key description: API key authentication parameters: UserId: name: userId in: path description: User ID required: true schema: type: string format: uuid example: "user123" schemas: User: type: object properties: id: type: string format: uuid description: User ID email: type: string format: email description: User email name: type: string description: User full name status: type: string enum: [active, inactive, suspended, pending] description: User account status created_at: type: string format: date-time description: Account creation timestamp updated_at: type: string format: date-time description: Last update timestamp profile: $ref: '#/components/schemas/UserProfile' required: - id - email - name - status - created_at - updated_at UserProfile: type: object properties: first_name: type: string last_name: type: string phone: type: string address: $ref: '#/components/schemas/Address' Address: type: object properties: street: type: string city: type: string state: type: string postal_code: type: string country: type: string format: ISO 3166-1 alpha-2 required: - street - city - state - postal_code - country CreateUserRequest: type: object properties: email: type: string format: email name: type: string minLength: 1 maxLength: 100 password: type: string minLength: 8 description: "Must contain at least one uppercase letter, one lowercase letter, and one number" profile: $ref: '#/components/schemas/UserProfile' required: - email - name - password UpdateUserRequest: type: object properties: email: type: string format: email name: type: string minLength: 1 maxLength: 100 status: type: string enum: [active, inactive, suspended, pending] profile: $ref: '#/components/schemas/UserProfile' UserResponse: type: object properties: data: $ref: '#/components/schemas/User' required: - data UserListResponse: type: object properties: data: type: array items: $ref: '#/components/schemas/User' pagination: $ref: '#/components/schemas/Pagination' required: - data - pagination Pagination: type: object properties: page: type: integer minimum: 1 description: Current page number per_page: type: integer minimum: 1 maximum: 100 description: Items per page total_pages: type: integer minimum: 1 description: Total number of pages total_count: type: integer minimum: 0 description: Total number of items required: - page - per_page - total_pages - total_count ErrorResponse: type: object properties: error: type: string description: Error message details: type: array items: type: object properties: field: type: string message: type: string required: - error responses: BadRequest: description: Bad request content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' example: error: "Validation failed" details: - field: "email" message: "Invalid email format" Unauthorized: description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' example: error: "Authentication required" NotFound: description: Resource not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' example: error: "User not found" TooManyRequests: description: Too many requests content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' example: error: "Rate limit exceeded" headers: X-RateLimit-Limit: schema: type: integer description: Request limit per time window X-RateLimit-Remaining: schema: type: integer description: Remaining requests in current window X-RateLimit-Reset: schema: type: integer description: Time when the rate limit resets (Unix timestamp) ``` ### 5. SDK Client Development **TypeScript SDK Example:** ```typescript // API SDK Client Implementation import axios, { AxiosInstance, AxiosRequestConfig, AxiosError } from 'axios'; // Configuration export interface APIConfig { baseURL: string; apiKey?: string; accessToken?: string; timeout?: number; retryAttempts?: number; retryDelay?: number; } // Error types export class APIError extends Error { constructor( public message: string, public statusCode: number, public details?: any ) { super(message); this.name = 'APIError'; } } export class ValidationError extends APIError { constructor( public fieldErrors: Record ) { super('Validation failed', 400, fieldErrors); this.name = 'ValidationError'; } } export class AuthenticationError extends APIError { constructor() { super('Authentication failed', 401); this.name = 'AuthenticationError'; } } export class RateLimitError extends APIError { constructor( public retryAfter?: number, public limit?: number, public remaining?: number ) { super('Rate limit exceeded', 429); this.name = 'RateLimitError'; } } // Main client export class APIClient { private axiosInstance: AxiosInstance; private config: APIConfig; constructor(config: APIConfig) { this.config = { timeout: 30000, retryAttempts: 3, retryDelay: 1000, ...config, }; this.axiosInstance = axios.create({ baseURL: this.config.baseURL, timeout: this.config.timeout, }); this.setupInterceptors(); } private setupInterceptors() { // Request interceptor this.axiosInstance.interceptors.request.use( (config) => { if (this.config.apiKey) { config.headers['X-API-Key'] = this.config.apiKey; } if (this.config.accessToken) { config.headers['Authorization'] = `Bearer ${this.config.accessToken}`; } return config; }, (error) => Promise.reject(error) ); // Response interceptor this.axiosInstance.interceptors.response.use( (response) => response.data, async (error: AxiosError) => { const config = error.config as any & { _retry?: number }; // Retry on 5xx errors if ( error.response?.status && error.response.status >= 500 && error.response.status < 600 && (!config._retry || config._retry < this.config.retryAttempts!) ) { config._retry = config._retry || 0; config._retry++; await this.delay(this.config.retryDelay! * config._retry); return this.axiosInstance(config); } // Handle specific errors if (error.response?.status === 401) { throw new AuthenticationError(); } if (error.response?.status === 429) { const retryAfter = parseInt(error.response.headers['retry-after'] || '0'); const limit = parseInt(error.response.headers['x-ratelimit-limit'] || '0'); const remaining = parseInt(error.response.headers['x-ratelimit-remaining'] || '0'); throw new RateLimitError(retryAfter, limit, remaining); } if (error.response?.status === 400) { throw new ValidationError(error.response.data.details); } throw new APIError( error.response?.data?.error || error.message, error.response?.status || 500, error.response?.data ); } ); } private delay(ms: number): Promise { return new Promise((resolve) => setTimeout(resolve, ms)); } // HTTP methods private async request( config: AxiosRequestConfig ): Promise { return this.axiosInstance.request(config); } async get( url: string, params?: Record, config?: AxiosRequestConfig ): Promise { return this.request({ method: 'GET', url, params, ...config, }); } async post( url: string, data?: any, config?: AxiosRequestConfig ): Promise { return this.request({ method: 'POST', url, data, ...config, }); } async put( url: string, data?: any, config?: AxiosRequestConfig ): Promise { return this.request({ method: 'PUT', url, data, ...config, }); } async patch( url: string, data?: any, config?: AxiosRequestConfig ): Promise { return this.request({ method: 'PATCH', url, data, ...config, }); } async delete( url: string, config?: AxiosRequestConfig ): Promise { return this.request({ method: 'DELETE', url, ...config, }); } } // Resource clients export class UsersClient { constructor(private apiClient: APIClient) {} async list(params?: ListUsersParams): Promise { return this.apiClient.get('/users', params); } async get(userId: string): Promise { return this.apiClient.get(`/users/${userId}`); } async create(data: CreateUserRequest): Promise { return this.apiClient.post('/users', data); } async update(userId: string, data: UpdateUserRequest): Promise { return this.apiClient.patch(`/users/${userId}`, data); } async delete(userId: string): Promise { return this.apiClient.delete(`/users/${userId}`); } } export class OrdersClient { constructor(private apiClient: APIClient) {} async list(params?: ListOrdersParams): Promise { return this.apiClient.get('/orders', params); } async get(orderId: string): Promise { return this.apiClient.get(`/orders/${orderId}`); } async create(data: CreateOrderRequest): Promise { return this.apiClient.post('/orders', data); } async cancel(orderId: string, reason?: string): Promise { return this.apiClient.post(`/orders/${orderId}/cancel`, { reason }); } } // Types export interface User { id: string; email: string; name: string; status: 'active' | 'inactive' | 'suspended' | 'pending'; created_at: string; updated_at: string; profile?: UserProfile; } export interface UserResponse { data: User; } export interface UserListResponse { data: User[]; pagination: { page: number; per_page: number; total_pages: number; total_count: number; }; } export interface CreateUserRequest { email: string; name: string; password: string; profile?: { first_name?: string; last_name?: string; phone?: string; }; } export interface UpdateUserRequest { email?: string; name?: string; status?: 'active' | 'inactive' | 'suspended' | 'pending'; profile?: CreateUserRequest['profile']; } export interface ListUsersParams { page?: number; per_page?: number; sort?: 'created_at' | 'name' | 'email'; order?: 'asc' | 'desc'; status?: 'active' | 'inactive' | 'suspended' | 'pending'; } export interface Order { id: string; user_id: string; items: OrderItem[]; total: number; status: OrderStatus; created_at: string; updated_at: string; } export interface OrderItem { id: string; product_id: string; quantity: number; price: number; subtotal: number; } export type OrderStatus = 'pending' | 'processing' | 'shipped' | 'delivered' | 'cancelled' | 'refunded'; export interface OrderResponse { data: Order; } export interface OrderListResponse { data: Order[]; pagination: { page: number; per_page: number; total_pages: number; total_count: number; }; } export interface CreateOrderRequest { items: { product_id: string; quantity: number; }[]; shipping_address: { street: string; city: string; state: string; postal_code: string; country: string; }; billing_address?: CreateOrderRequest['shipping_address']; } export interface ListOrdersParams { page?: number; per_page?: number; status?: OrderStatus; } // Factory function export function createAPIClient(config: APIConfig) { const apiClient = new APIClient(config); return { users: new UsersClient(apiClient), orders: new OrdersClient(apiClient), }; } // Usage example const api = createAPIClient({ baseURL: 'https://api.example.com/v1', apiKey: process.env.API_KEY, }); async function main() { try { // List users const users = await api.users.list({ page: 1, per_page: 20, status: 'active', }); console.log(`Found ${users.pagination.total_count} users`); // Create user const user = await api.users.create({ email: 'john@example.com', name: 'John Doe', password: 'SecurePassword123!', }); console.log(`Created user: ${user.data.id}`); // Create order const order = await api.orders.create({ items: [ { product_id: 'product123', quantity: 2, }, ], shipping_address: { street: '123 Main St', city: 'San Francisco', state: 'CA', postal_code: '94102', country: 'US', }, }); console.log(`Created order: ${order.data.id}`); } catch (error) { if (error instanceof ValidationError) { console.error('Validation failed:', error.fieldErrors); } else if (error instanceof AuthenticationError) { console.error('Authentication failed'); } else if (error instanceof RateLimitError) { console.error('Rate limit exceeded'); } else { console.error('Error:', error); } } } ``` --- ## Conclusion The API Architect Agent provides comprehensive API design and implementation capabilities across REST, GraphQL, and gRPC. By following this specification, the agent delivers: 1. **API Design**: Resource-oriented, uniform interface, RESTful principles 2. **Security**: Authentication, authorization, rate limiting, input validation 3. **Performance**: Caching, optimization, monitoring strategies 4. **Documentation**: OpenAPI specifications, comprehensive guides 5. **SDK Development**: Type-safe client libraries in multiple languages 6. **Testing**: Contract testing, integration testing, performance testing 7. **API Gateway**: Configuration for routing, transformation, and security This agent specification ensures production-ready APIs that are secure, performant, and developer-friendly across all use cases and requirements.