Design or review an HTTP/REST/GraphQL API for versioning, pagination, error shapes, idempotency, auth, and evolvability. Use when asked to "design an API", "shape the endpoints", "design the schema", "add a new endpoint", "review this API", or when building/modifying a public or internal HTTP surface. Complements `design-an-interface` (which is interface-agnostic) by covering HTTP-specific concerns like status codes, cache headers, and breaking-change management.
80
100%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Invocation points:
<core_principle> CALLERS OUTLIVE YOUR ASSUMPTIONS. An API you ship today has to keep working when your internals change, when the mobile app version two is still in use, and when a third party integrates against it. Design for extension, not just for the current caller.
HONEST STATUS CODES. 200 OK with {"error": "not found"} is a lie. 404 says not found. Use the HTTP semantics the protocol offers — HTTP clients, caches, and intermediaries rely on them.
PAGINATION IS NON-OPTIONAL. Any list endpoint that doesn't paginate will eventually get a request for "all records" that kills your database. </core_principle>
Answer, or ask (one round, 1–3 questions):
/v1/) / header-based / GraphQL schema evolution.POST /users, not POST /createUser./users/42, not /user/42./users/42/sessions/3. Otherwise flat: /sessions/3?userId=42.POST /users/42:deactivate (colon syntax) or POST /users/42/actions/deactivate.user(id), createUser(input), deactivateUser(id).createUser(input: CreateUserInput!).| Method | Intent | Idempotent? | Default success |
|---|---|---|---|
| GET | Read | Yes | 200, or 304 if conditional |
| POST | Create or non-idempotent action | No | 201 with Location on create, 200 on action |
| PUT | Replace (full-object) | Yes | 200 with body, or 204 |
| PATCH | Partial update | No (usually) | 200 with body |
| DELETE | Remove | Yes | 204 |
Errors:
Retry-AfterRetry-AfterNever 200-with-error-body. Never 500 for a 4xx cause.
errors[]) for transport-level failures. Domain errors (validation, not-found, forbidden) go in the typed return — use a union or result type.null on a field is meaningful, not a signal of generic failure.limit, return nextCursor when more exists. Scales, stable under writes.limit (e.g., 200).edges, pageInfo) if the ecosystem expects it; otherwise a simpler {items, nextCursor} is fine.Standardize one shape and use it everywhere. Example REST:
{
"error": {
"code": "user_not_found",
"message": "No user with id 42",
"details": { "userId": 42 },
"requestId": "req_abc123"
}
}code is machine-readable; stable; documented.message is human-readable; can change.details carries structured context.requestId lets callers report bugs.Errors don't leak stack traces, file paths, or internal queries.
Idempotency-Key: <uuid>; server dedupes for a window.If-Match on PUT/PATCH)./v2/), sunset headers on /v1/, deprecation window communicated. Or, for GraphQL, @deprecated on fields with a migration note.If this is a review, produce findings in the same shape as security-review / review — file:line, category, recommendation.
If this is a new design, produce:
## <API name>
### Scope
<what the API is for, who calls it>
### Endpoints / Operations
- `POST /users` — create user. Request: `{email, name}`. Response 201: `{id, email, name, createdAt}` + `Location: /users/<id>`. Errors: 409 email taken, 422 invalid.
- ...
### Auth
<model + where to put the credential>
### Pagination
<cursor shape, max limit>
### Error shape
<one canonical shape>
### Idempotency / concurrency
<rules>
### Versioning
<stance + how breaking changes will be handled>
### OpenAPI / SDL
<link or inline>Append architectural decisions to .gsd/DECISIONS.md.
<anti_patterns>
{"error": "..."}. Lies to caches, proxies, retry libraries.GET /users without a limit cap will bite you.</anti_patterns>
<success_criteria>
.gsd/DECISIONS.md.</success_criteria>
33c00aa
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.