# Pathrule Pattern: REST / HTTP API Design (1.0.0)
# ::pathrule:package:rest-api-design

### [RULE] Resource naming and HTTP semantics  (path: /src/api)
<!-- scope: folder | priority: high | strict -->

URLs name resources with plural nouns; the HTTP method carries the verb and the status code carries the result. Never tunnel an action through a path segment or hide a failure inside a 200 body.

- Use plural noun collections (`/orders`, `/users/{id}/invoices`) and keep nesting at most two levels deep; never `POST /createOrder` or `/orders/get`.
- Map methods correctly: `GET` reads (safe), `POST` creates, `PUT` replaces, `PATCH` partially updates, `DELETE` removes. `GET`, `PUT`, and `DELETE` must be idempotent.
- Return the precise status: `201` with a `Location` header on create, `200` on read/update, `204` on a body-less delete, `400`/`422` for invalid input, `401`/`403` for auth, `404` for missing, `409` for conflicts, `429` when rate limited.
- Never return `200` with `{ "success": false }`; let the status line signal failure so clients and proxies can react without parsing the body.

---

### [RULE] Idempotency keys on unsafe writes  (path: /src/api)
<!-- scope: folder | priority: high | advisory -->

Networks drop responses, so clients retry; without deduplication a retried `POST` charges twice or creates duplicate rows. Make unsafe writes safe to retry with a client-supplied key.

- Accept an `Idempotency-Key` request header on every `POST` (and any non-idempotent endpoint) that creates resources, money movement, or external side effects.
- Persist the key with the request fingerprint and the stored response; a replay with the same key returns the original result without re-executing the operation.
- Scope keys per endpoint and per authenticated principal, set a retention TTL (commonly 24 hours), and return `409` if the same key arrives with a different request body.
- While the first request is still in flight, return `409` (or `425 Too Early`) for a concurrent replay rather than running the operation twice.

---

### [MEMORY] Error envelope: RFC 9457 problem details  (path: /src/api)

Every error returns an RFC 9457 problem document (the successor to RFC 7807), served as `application/problem+json`. One envelope across the whole API means clients write error handling once.

- Always include `type` (a stable URI identifying the problem class), `title`, and `status`; add `detail` for a human-readable specific message and `instance` for the affected resource.
- Make `type` a real, documented URI per problem class (for example `https://api.example.com/problems/insufficient-funds`); reuse it so clients can branch on it instead of parsing prose.
- Add custom extension members for machine use (`errors` array for field-level validation, `traceId` for correlation, `balance` for domain context); never repurpose the standard members.
- Keep `status` in the body equal to the HTTP status line, and never leak stack traces or internal identifiers into `detail`.

---

### [MEMORY] Collection pagination and list contracts  (path: /src/api)

Collections are paginated with cursor (keyset) pagination, the pattern used by Stripe, GitHub, and Slack. Offset/`OFFSET` paging drifts when rows are inserted or deleted and degrades as the database counts and skips rows at scale.

- Accept `limit` plus an opaque `cursor` (or `after`/`before`); the cursor encodes the sort key and id of the last item so clients cannot tamper with or reverse-engineer it.
- Enforce a default and a hard maximum page size (for example default `20`, max `100`); clamp oversized `limit` values instead of honoring `limit=1000000`.
- Return a stable envelope: a `data` array plus a `next_cursor` (null on the last page) or a `has_more` boolean; never make clients guess where the list ends.
- Sort on a deterministic, indexed tiebreaker (such as `created_at`, `id`) so the cursor maps to a single position and page boundaries stay consistent.

---

### [SKILL] rest-api-design-review  (path: /)

---
name: rest-api-design-review
description: Run this checklist before merging any new or changed HTTP/REST endpoint. Covers resource naming, HTTP method and status semantics, RFC 9457 error envelopes, cursor pagination, idempotency keys, and deprecation discipline.
---

# REST / HTTP API design review

- [ ] Paths name resources with plural nouns and nest at most two levels; no verbs in the path.
- [ ] HTTP method matches intent and `GET`/`PUT`/`DELETE` are idempotent; safe methods cause no side effects.
- [ ] Status codes are precise: `201`+`Location` on create, `204` on empty delete, `400`/`422`, `401`/`403`, `404`, `409`, `429`; no `200` wrapping a failure.
- [ ] All errors return an RFC 9457 `application/problem+json` document with `type`, `title`, `status`, and a documented stable `type` URI.
- [ ] Field-level validation errors and a `traceId` are carried as problem-detail extension members, with no stack traces leaked.
- [ ] Collection endpoints use opaque cursor pagination with `limit`, a clamped max page size, and a `next_cursor`/`has_more` last-page signal.
- [ ] Unsafe `POST` mutations accept an `Idempotency-Key` and return the stored result on replay instead of re-executing.
- [ ] Breaking changes ship under a new version; the old version sends `Deprecation` and `Sunset` headers (RFC 9745 / RFC 8594).
- [ ] Retired versions return `410 Gone` after the sunset date, not `404` or `500`, and a migration guide is linked.
- [ ] The endpoint is documented in the OpenAPI spec with request/response schemas and example error payloads.
