{"name":"design-rest-api","description":"Designs a clean REST API before you build it - resource names, HTTP methods and status codes, request and response shapes, pagination, filtering, errors, versioning and auth - written down as a short contract the front end can rely on. Use when the user is planning API routes or endpoints, choosing status codes or an error format, or tidying an inconsistent API.","category":"backend","tags":["api","rest","architecture"],"models":["any"],"proven":false,"passing_families":0,"model_testing":"Not yet model-tested; testing Jan 2027","url":"https://theskillvault.ai/skills/design-rest-api","api_url":"https://theskillvault.ai/api/skills/design-rest-api","raw_url":"https://theskillvault.ai/api/skills/design-rest-api/raw","body":"# Design a REST API\n\nA good API is boring and predictable. Decide the rules once, write them down, and every endpoint follows them.\n\n## When to use\n- You are about to build the backend for an app and want endpoints planned first.\n- Your routes mix styles, such as `/getUsers` next to `/orders/list`.\n- A front-end or mobile developer needs a contract to build against.\n\n## When not to use\n- You only need to call someone else's API. Read their docs instead.\n\n## Steps\n1. List the nouns your app stores: users, projects, invoices. Each becomes a plural resource such as `/projects`.\n2. Map actions to methods: `GET` reads, `POST` creates, `PATCH` updates part, `PUT` replaces, `DELETE` removes.\n3. Nest only one level for ownership: `/projects/{id}/tasks`. Go flat beyond that.\n4. Pick status codes and stick to them (table below).\n5. Define one error shape for every endpoint.\n6. Add pagination to every list from day one, with a `limit` and a cursor or page.\n7. Use query parameters for filters and sorting: `?status=open&sort=-created_at`.\n8. Decide auth per route: public, signed-in, owner-only, admin.\n9. Version the API (`/v1`) or commit to only additive changes.\n10. Write it down as an OpenAPI file or a short Markdown table, and review it before coding.\n\n| Situation | Status |\n| --- | --- |\n| Read or update worked | 200 |\n| Created | 201 plus the new resource |\n| Deleted, nothing to return | 204 |\n| Bad input | 400 or 422 with field errors |\n| Not signed in | 401 |\n| Signed in, not allowed | 403 (or 404 to hide it exists) |\n| Not found | 404 |\n| Too many requests | 429 |\n\n```json\n{ \"error\": { \"code\": \"validation_failed\", \"message\": \"Email is required\", \"fields\": { \"email\": \"required\" } } }\n```\n\n## Gotchas\n- Never trust an id from the URL alone. Check the signed-in user owns the record.\n- Never return password hashes, tokens or internal fields. Use explicit response shapes.\n- Verbs in paths (`/createUser`) drift fast. Let the method carry the verb.\n- Unpaginated lists work in testing and fall over in production.\n\n## Portability\nWorks with any framework: Next.js route handlers, Express, Hono, FastAPI or Rails. If you use GraphQL or tRPC instead, the same rules on naming, errors and auth still apply.\n\n## Example prompt\n\"Design the REST endpoints for a simple project tracker with projects, tasks and comments. Include status codes and an error format.\"\n\n## Done when\n- Every endpoint has a method, path, auth rule, request and response shape.\n- Errors share one format and lists are paginated.\n- The contract is saved in the repo (OpenAPI or Markdown).\n\n---\nAdapted from \"api-design-principles\" in wshobson/agents (MIT, Copyright (c) 2024 Seth Hobson). See LICENSE.txt.","files":["LICENSE.txt"],"license":"MIT","license_name":"MIT License","license_url":"https://opensource.org/license/mit","attribution":"Based on work by Seth Hobson (wshobson/agents, api-design-principles) (Copyright (c) 2024 Seth Hobson, MIT License), https://github.com/wshobson/agents/tree/7e2fb559cf4b824b27f1fec49fe88f7511066d26/plugins/backend-development/skills/api-design-principles; adapted by TheSkillVault, https://theskillvault.ai","install":{"claude_code":"curl -fsSL --create-dirs 'https://theskillvault.ai/api/skills/design-rest-api/raw' -o ~/'.claude/skills/design-rest-api/SKILL.md' && curl -fsSL --create-dirs 'https://theskillvault.ai/api/skills/design-rest-api/files/LICENSE.txt' -o ~/'.claude/skills/design-rest-api/LICENSE.txt'","cursor":"curl -fsSL --create-dirs 'https://theskillvault.ai/api/skills/design-rest-api/raw' -o '.cursor/skills/design-rest-api/SKILL.md' && curl -fsSL --create-dirs 'https://theskillvault.ai/api/skills/design-rest-api/files/LICENSE.txt' -o '.cursor/skills/design-rest-api/LICENSE.txt'","agents":"curl -fsSL --create-dirs 'https://theskillvault.ai/api/skills/design-rest-api/raw' -o '.agents/skills/design-rest-api/SKILL.md' && curl -fsSL --create-dirs 'https://theskillvault.ai/api/skills/design-rest-api/files/LICENSE.txt' -o '.agents/skills/design-rest-api/LICENSE.txt'","mcp_url":"https://theskillvault.ai/mcp","cursor_mcp_deeplink":"cursor://anysphere.cursor-deeplink/mcp/install?name=theskillvault&config=eyJ1cmwiOiJodHRwczovL3RoZXNraWxsdmF1bHQuYWkvbWNwIn0%3D","mcp_config":{"mcpServers":{"theskillvault":{"url":"https://theskillvault.ai/mcp"}}}},"bundles":[],"tested_on":[{"family":"chatgpt","name":"ChatGPT","outcome":null,"date":null,"source":null,"counts":false,"stale":false},{"family":"claude","name":"Claude","outcome":null,"date":null,"source":null,"counts":false,"stale":false},{"family":"gemini","name":"Gemini","outcome":null,"date":null,"source":null,"counts":false,"stale":false},{"family":"grok","name":"Grok","outcome":null,"date":null,"source":null,"counts":false,"stale":false},{"family":"llama","name":"Llama","outcome":null,"date":null,"source":null,"counts":false,"stale":false},{"family":"deepseek","name":"DeepSeek","outcome":null,"date":null,"source":null,"counts":false,"stale":false},{"family":"mistral","name":"Mistral","outcome":null,"date":null,"source":null,"counts":false,"stale":false},{"family":"qwen","name":"Qwen","outcome":null,"date":null,"source":null,"counts":false,"stale":false},{"family":"kimi","name":"Kimi K","outcome":null,"date":null,"source":null,"counts":false,"stale":false}],"proven_rule":{"threshold":5,"window_days":365,"computed_at":"2026-11-02T03:20:33.817Z"}}