Massive training corpus for AI coding models containing: - 10 JSONL training datasets (641+ examples across coding, reasoning, planning, architecture, communication, debugging, security, workflows, error handling, UI/UX) - 11 agent behavior specifications (explorer, planner, reviewer, debugger, executor, UI designer, Linux admin, kernel engineer, security architect, automation engineer, API architect) - 6 skill definition files (coding, API engineering, kernel, Linux server, security architecture, server automation, UI/UX) - Master README with project origin story and philosophy Built by Pony Alpha 2 to help AI models learn expert-level coding approaches.
2373 lines
59 KiB
Markdown
2373 lines
59 KiB
Markdown
# 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<string, string[]>
|
|
) {
|
|
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<void> {
|
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
}
|
|
|
|
// HTTP methods
|
|
private async request<T>(
|
|
config: AxiosRequestConfig
|
|
): Promise<T> {
|
|
return this.axiosInstance.request<T>(config);
|
|
}
|
|
|
|
async get<T>(
|
|
url: string,
|
|
params?: Record<string, any>,
|
|
config?: AxiosRequestConfig
|
|
): Promise<T> {
|
|
return this.request<T>({
|
|
method: 'GET',
|
|
url,
|
|
params,
|
|
...config,
|
|
});
|
|
}
|
|
|
|
async post<T>(
|
|
url: string,
|
|
data?: any,
|
|
config?: AxiosRequestConfig
|
|
): Promise<T> {
|
|
return this.request<T>({
|
|
method: 'POST',
|
|
url,
|
|
data,
|
|
...config,
|
|
});
|
|
}
|
|
|
|
async put<T>(
|
|
url: string,
|
|
data?: any,
|
|
config?: AxiosRequestConfig
|
|
): Promise<T> {
|
|
return this.request<T>({
|
|
method: 'PUT',
|
|
url,
|
|
data,
|
|
...config,
|
|
});
|
|
}
|
|
|
|
async patch<T>(
|
|
url: string,
|
|
data?: any,
|
|
config?: AxiosRequestConfig
|
|
): Promise<T> {
|
|
return this.request<T>({
|
|
method: 'PATCH',
|
|
url,
|
|
data,
|
|
...config,
|
|
});
|
|
}
|
|
|
|
async delete<T>(
|
|
url: string,
|
|
config?: AxiosRequestConfig
|
|
): Promise<T> {
|
|
return this.request<T>({
|
|
method: 'DELETE',
|
|
url,
|
|
...config,
|
|
});
|
|
}
|
|
}
|
|
|
|
// Resource clients
|
|
export class UsersClient {
|
|
constructor(private apiClient: APIClient) {}
|
|
|
|
async list(params?: ListUsersParams): Promise<UserListResponse> {
|
|
return this.apiClient.get<UserListResponse>('/users', params);
|
|
}
|
|
|
|
async get(userId: string): Promise<UserResponse> {
|
|
return this.apiClient.get<UserResponse>(`/users/${userId}`);
|
|
}
|
|
|
|
async create(data: CreateUserRequest): Promise<UserResponse> {
|
|
return this.apiClient.post<UserResponse>('/users', data);
|
|
}
|
|
|
|
async update(userId: string, data: UpdateUserRequest): Promise<UserResponse> {
|
|
return this.apiClient.patch<UserResponse>(`/users/${userId}`, data);
|
|
}
|
|
|
|
async delete(userId: string): Promise<void> {
|
|
return this.apiClient.delete<void>(`/users/${userId}`);
|
|
}
|
|
}
|
|
|
|
export class OrdersClient {
|
|
constructor(private apiClient: APIClient) {}
|
|
|
|
async list(params?: ListOrdersParams): Promise<OrderListResponse> {
|
|
return this.apiClient.get<OrderListResponse>('/orders', params);
|
|
}
|
|
|
|
async get(orderId: string): Promise<OrderResponse> {
|
|
return this.apiClient.get<OrderResponse>(`/orders/${orderId}`);
|
|
}
|
|
|
|
async create(data: CreateOrderRequest): Promise<OrderResponse> {
|
|
return this.apiClient.post<OrderResponse>('/orders', data);
|
|
}
|
|
|
|
async cancel(orderId: string, reason?: string): Promise<OrderResponse> {
|
|
return this.apiClient.post<OrderResponse>(`/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.
|