Files
global-skills/skills/api-design/SKILL.md
T

104 lines
4.0 KiB
Markdown
Raw Normal View History

---
name: api-design
description: >
Designs RESTful APIs, typed schema membranes, request/response validation contracts, and API documentation.
Use when creating or modifying API routes, defining request/response schemas, designing error responses,
or standardizing API contracts.
concerns: [security, system-one-balance]
---
# API Design & Membrane Architecture
Governs API design and boundary membranes, ensuring typed validation, input clamping, predictable HTTP semantics, and consistent structured error contracts.
---
## Phase 0: Setup and Protocols
1. **Membrane Principles**:
- **Boundary Isolation**: Route handlers serve as the transport membrane. Core business services and data access layers remain transport-agnostic (never import web framework request objects or HTTP status codes into domain logic).
- **Contract-First Validation**: Define typed schemas (e.g. Pydantic, Zod, TypeScript interfaces) before implementing endpoint logic.
- **Dependency Injection**: Inject database sessions, repositories, and authentication state into route handlers; avoid importing global singletons directly.
---
## Phase 1: Ingest and Check
1. **Identify Endpoint Requirements**:
- Resource name, target path, HTTP method (`GET`, `POST`, `PUT`, `PATCH`, `DELETE`).
- Expected input payload, query parameters, route path variables, and headers.
- Response model, status codes (200, 201, 204), and error failure modes.
2. **Input Boundary Clamping**:
- Enforce explicit upper bounds on all strings (e.g. `min_length=1`, `max_length=200` for names; `max_length=50000` for content).
- Enforce pagination limits: `1 <= limit <= 50` (or `100` max).
- Constrain array inputs: clamp batch endpoints to maximum batch sizes.
---
## Phase 2: Processing (Core Logic)
### Step 1: Define Typed Contracts
```python
# 1. Request & Response Schemas
class ResourceCreateRequest(BaseModel):
name: str = Field(..., min_length=1, max_length=200)
description: str | None = Field(None, max_length=2000)
class ResourceResponse(BaseModel):
id: str
name: str
description: str | None = None
created_at: datetime
```
### Step 2: Implement Route Handler
```python
# 2. Endpoint Implementation
@router.post("/resources", response_model=ResourceResponse, status_code=201)
async def create_resource(
payload: ResourceCreateRequest,
repo: ResourceRepository = Depends(get_resource_repo),
):
entity = await repo.create(payload.model_dump())
return ResourceResponse.model_validate(entity)
```
### Step 3: Enforce HTTP & Error Semantics
- **HTTP Methods**:
- `POST`: Resource creation / command execution (201 Created or 200 OK).
- `GET`: Idempotent retrieval (200 OK).
- `PUT`: Full resource replacement (200 OK).
- `PATCH`: Partial state update (200 OK).
- `DELETE`: Resource removal (204 No Content).
- **Structured Error Responses**:
- Return standardized error objects (e.g. RFC 7807 problem details or structured error payloads):
```json
{
"error": {
"code": "RESOURCE_NOT_FOUND",
"message": "Resource with id 'xyz' was not found",
"details": {}
}
}
```
- Standard status codes: 400 (Validation), 401 (Unauthenticated), 403 (Unauthorized), 404 (Not Found), 409 (Conflict).
- **Timezone Invariant**: Always serialize timestamps in UTC using ISO-8601 (`YYYY-MM-DDTHH:MM:SSZ`).
---
## Phase 3: The System One Balance Pass
- **Augment, Don't Handcuff**:
- Do NOT over-complicate simple internal endpoints with bloated enterprise middleware.
- Keep route handlers thin: route logic should unpack requests, call services/repos, and map to response models.
- Fail open on safe internal queries; enforce rigorous clamping at external boundary layers.
---
## Phase 4: Output Execution & Verification
1. Verify:
- Route docstrings populate OpenAPI / Swagger schemas accurately.
- All response models are strongly typed without bare `dict` or `Any` escapes.
- Input clamping fields prevent memory exhaustion and DoS.
2. Deliver the schema definition, route implementation, and corresponding test case.