Skip to content
Back to skills

Api Design Principles

ASecurity

REST API design decisions — URL conventions, error contracts, versioning, pagination, idempotency, auth patterns.

  • 19 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 19, 2026
ai-agentspythonbashfastapiapisecurity

Works with

  • cursor
  • cli
  • api

Security analysis

A100/100

Pro scans all 6 files and shows the line behind each finding

Scanned October 19, 2026

npx -y skills add sawrus/agent-guides --skill api-design-principles --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Api Design Principles?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Api Design Principles
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/sawrus-api-design-principles/badge)](https://www.skillsdirectory.com/skills/sawrus-api-design-principles)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: api-design-principles
type: skill
description: REST API design decisions — URL conventions, error contracts, versioning, pagination, idempotency, auth patterns.
related-rules:
  - api-design-guide.md
  - security-guide.md
allowed-tools: Read, Write, Edit, Bash
---

# API Design Principles Skill

> Practical reference for consistent, production-ready API design decisions.

## URL & Method Conventions

```
✅ Plural nouns, kebab-case, resource hierarchy max 2 levels
   GET    /users/{id}
   POST   /orders
   PATCH  /orders/{id}
   DELETE /orders/{id}
   POST   /orders/{id}/cancel      ← actions as sub-resource verbs

❌ Verbs in base path
   POST /createOrder
   GET  /getUser?id=123
```

| Operation | Method | Success code |
|---|---|---|
| Create | POST | 201 |
| Read | GET | 200 |
| Full update | PUT | 200 |
| Partial update | PATCH | 200 |
| Delete | DELETE | 204 |
| Async action | POST | 202 |

## Standard Error Contract

Every error must follow the same shape — never return raw exception messages.

```json
{
  "error": {
    "code": "ORDER_NOT_FOUND",
    "message": "Order ord_123 not found",
    "details": [{ "field": "items[0].quantity", "issue": "must be > 0" }],
    "request_id": "req_abc123"
  }
}
```

```python
# FastAPI
raise HTTPException(
    status_code=404,
    detail={"code": "ORDER_NOT_FOUND", "message": f"Order {id} not found",
            "request_id": request.state.request_id}
)
```

## Pagination

**Cursor-based** — preferred for live/large datasets:
```python
class PaginatedResponse(BaseModel, Generic[T]):
    items: List[T]
    next_cursor: Optional[str] = None   # base64-encoded, opaque to client

def encode_cursor(last_id: int) -> str:
    return base64.b64encode(str(last_id).encode()).decode()
```

**Offset-based** — only for small static datasets where total count is cheap.

## Versioning

```
URL versioning for breaking changes:   /api/v1/orders → /api/v2/orders
Header for minor variations:           Accept: application/vnd.myapi.v2+json

Rules:
- v1 stays alive ≥ 6 months after v2 launch
- Deprecated: return  Deprecation: true  +  Sunset: <date>  headers
- Never remove a field without a major version bump
```

## Idempotency (POST mutations)

```python
@router.post("/orders", status_code=201)
async def create_order(
    body: CreateOrderRequest,
    idempotency_key: Optional[str] = Header(None, alias="X-Idempotency-Key"),
):
    if idempotency_key:
        cached = await redis.get(f"idempotency:{idempotency_key}")
        if cached:
            return JSONResponse(json.loads(cached), status_code=200)

    order = await order_service.create(body)

    if idempotency_key:
        await redis.setex(f"idempotency:{idempotency_key}", 86400, order.model_dump_json())
    return order
```

## Security Checklist

- [ ] Auth middleware applied before handler — never inside handler
- [ ] Ownership check: `if resource.owner_id != current_user.id: raise 403`
- [ ] All inputs validated via Pydantic/Zod before use
- [ ] Rate limiting on public + auth endpoints
- [ ] No secrets or PII in URL parameters
- [ ] CORS: no `allow_origins=["*"]` in production
- [ ] Response never leaks internal IDs, stack traces, or system paths

## Response Design Checklist

- [ ] Consistent envelope: `{ data: T }` or flat — choose one, never mix
- [ ] Dates always ISO 8601 with timezone: `2024-03-15T14:30:00Z`
- [ ] Monetary values: string decimal or integer cents — never float
- [ ] Nullable fields explicit in schema (not absent)
- [ ] List responses always return array, never `null` when empty

Files in this skill

  • SKILL.md3.5 KB
  • assets/api-design-checklist.md3.8 KB
  • assets/rest-api-template.py5.2 KB
  • references/graphql-schema-design.md8.8 KB
  • references/rest-best-practices.md7.4 KB
  • resources/implementation-playbook.md12.7 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.