104 lines
4.0 KiB
Markdown
104 lines
4.0 KiB
Markdown
---
|
|||
|
|
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.
|