API Design
When to Apply
- Classification: feature, architecture-change, hotfix (if touching API endpoints)
- Phase: /implement (design & build), /review (compliance check), /test (contract verification)
- Trigger: Task involves creating, modifying, or deprecating API endpoints
Conventions
Customize after /app-init: Replace these generic conventions with your project's ADR decisions.
Endpoint Naming
- Use nouns for resources, not verbs:
GET /users not GET /getUsers
- Plural resource names:
/users, /orders, /products
- Nested resources for relationships:
/users/:id/orders
- Use kebab-case for multi-word paths:
/order-items
HTTP Methods
| Action |
Method |
Success Status |
Idempotent |
| List |
GET |
200 |
Yes |
| Get one |
GET |
200 |
Yes |
| Create |
POST |
201 |
No |
| Full update |
PUT |
200 |
Yes |
| Partial update |
PATCH |
200 |
No |
| Delete |
DELETE |
204 |
Yes |
Error Response Format
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Email is required",
"details": {
"field": "email",
"constraint": "required"
}
}
}
Standard Error Codes
| HTTP Status |
When |
Error Code Pattern |
| 400 |
Invalid input |
VALIDATION_ERROR, INVALID_FORMAT |
| 401 |
Not authenticated |
UNAUTHORIZED |
| 403 |
Not permitted |
FORBIDDEN |
| 404 |
Resource not found |
NOT_FOUND |
| 409 |
Conflict (duplicate) |
CONFLICT, DUPLICATE |
| 422 |
Business rule violation |
UNPROCESSABLE |
| 429 |
Rate limited |
RATE_LIMITED |
| 500 |
Server error |
INTERNAL_ERROR |
Pagination
{
"data": [...],
"pagination": {
"total": 100,
"page": 1,
"per_page": 20,
"has_next": true
}
}
Versioning
- URL path versioning:
/api/v1/users
- Breaking changes require new version
- Deprecation: add
Sunset header with date, keep old version for N months
Input Validation
- Validate at the controller/route level BEFORE business logic
- Return ALL validation errors at once (batch), not one at a time
- Sanitize strings: trim whitespace, escape HTML where applicable
- Enforce max lengths on all string fields
Checklist
During /implement:
During /review:
Heading-Scoped Read Note
For phase-entry loading, read only:
Load Conventions, Anti-Patterns, and References on full read or cache miss only.
Anti-Patterns
- God endpoint: One endpoint that does everything based on query params. Split into specific endpoints.
- Verb in URL:
POST /createUser → POST /users
- Inconsistent naming: Mixing
/user and /products (singular vs plural)
- Swallowing errors: Catching exceptions and returning 200 with
{ success: false }
- Leaking internals: Returning DB column names directly as API fields without mapping
- Missing 404: Returning empty 200 instead of 404 when resource doesn't exist
- Unbounded lists: List endpoints without pagination or default limits
References
- Project ADR:
docs/adr/ADR-002-project-architecture.md § API Design
- Security guardrails:
.agent/rules/security_guardrails.md (A01: Access Control, A03: Injection)
- Spec template:
.agentcortex/templates/spec-app-feature.md § API Contract
1---2name: kbwen-agentic-os3description: <!-- This is a SCAFFOLD skill. When /app-init runs in a downstream project, -->4---5<!-- This is a SCAFFOLD skill. When /app-init runs in a downstream project, -->6<!-- it customizes this file based on the project's ADR tech stack. -->7<!-- If this file has NOT been customized, the AI should treat it as generic guidance. -->89# API Design1011## When to Apply1213- **Classification**: feature, architecture-change, hotfix (if touching API endpoints)14- **Phase**: /implement (design & build), /review (compliance check), /test (contract verification)15- **Trigger**: Task involves creating, modifying, or deprecating API endpoints1617## Conventions1819> **Customize after /app-init**: Replace these generic conventions with your project's ADR decisions.2021### Endpoint Naming22- Use nouns for resources, not verbs: `GET /users` not `GET /getUsers`23- Plural resource names: `/users`, `/orders`, `/products`24- Nested resources for relationships: `/users/:id/orders`25- Use kebab-case for multi-word paths: `/order-items`2627### HTTP Methods28| Action | Method | Success Status | Idempotent |29|---|---|---|---|30| List | GET | 200 | Yes |31| Get one | GET | 200 | Yes |32| Create | POST | 201 | No |33| Full update | PUT | 200 | Yes |34| Partial update | PATCH | 200 | No |35| Delete | DELETE | 204 | Yes |3637### Error Response Format38```json39{40 "error": {41 "code": "VALIDATION_ERROR",42 "message": "Email is required",43 "details": {44 "field": "email",45 "constraint": "required"46 }47 }48}49```5051### Standard Error Codes52| HTTP Status | When | Error Code Pattern |53|---|---|---|54| 400 | Invalid input | VALIDATION_ERROR, INVALID_FORMAT |55| 401 | Not authenticated | UNAUTHORIZED |56| 403 | Not permitted | FORBIDDEN |57| 404 | Resource not found | NOT_FOUND |58| 409 | Conflict (duplicate) | CONFLICT, DUPLICATE |59| 422 | Business rule violation | UNPROCESSABLE |60| 429 | Rate limited | RATE_LIMITED |61| 500 | Server error | INTERNAL_ERROR |6263### Pagination64```json65{66 "data": [...],67 "pagination": {68 "total": 100,69 "page": 1,70 "per_page": 20,71 "has_next": true72 }73}74```7576### Versioning77- URL path versioning: `/api/v1/users`78- Breaking changes require new version79- Deprecation: add `Sunset` header with date, keep old version for N months8081### Input Validation82- Validate at the controller/route level BEFORE business logic83- Return ALL validation errors at once (batch), not one at a time84- Sanitize strings: trim whitespace, escape HTML where applicable85- Enforce max lengths on all string fields8687## Checklist8889During /implement:90- [ ] Every endpoint has input validation91- [ ] Every endpoint returns consistent error format92- [ ] Every endpoint has proper auth check (or explicit `public` annotation)93- [ ] Pagination for list endpoints94- [ ] Rate limiting consideration (at least documented in spec)95- [ ] No sensitive data in URL parameters (use body or headers)96- [ ] Request/response examples in spec match implementation9798During /review:99- [ ] No N+1 query patterns in list endpoints100- [ ] Proper HTTP status codes (not everything is 200)101- [ ] Idempotency for PUT/DELETE102- [ ] Error messages don't leak internal details (stack traces, SQL, paths)103- [ ] CORS configured per ADR policy104105## Heading-Scoped Read Note106107For phase-entry loading, read only:108- `When to Apply`109- `Checklist`110111Load `Conventions`, `Anti-Patterns`, and `References` on full read or cache miss only.112113## Anti-Patterns114115- **God endpoint**: One endpoint that does everything based on query params. Split into specific endpoints.116- **Verb in URL**: `POST /createUser` → `POST /users`117- **Inconsistent naming**: Mixing `/user` and `/products` (singular vs plural)118- **Swallowing errors**: Catching exceptions and returning 200 with `{ success: false }`119- **Leaking internals**: Returning DB column names directly as API fields without mapping120- **Missing 404**: Returning empty 200 instead of 404 when resource doesn't exist121- **Unbounded lists**: List endpoints without pagination or default limits122123## References124125- Project ADR: `docs/adr/ADR-002-project-architecture.md` § API Design126- Security guardrails: `.agent/rules/security_guardrails.md` (A01: Access Control, A03: Injection)127- Spec template: `.agentcortex/templates/spec-app-feature.md` § API Contract