{"record":{"id":"4500fc73124b22f0","repo":"affaan-m/ECC","slug":"not-found-4500fc","errorCode":"not_found","errorMessage":"not_found","messagePattern":"not_found","errorType":"http","errorClass":null,"httpStatus":404,"severity":"error","filePath":"skills/api-design/SKILL.md","lineNumber":316,"sourceCode":"### Token-Based Auth\n\n```\n# Bearer token in Authorization header\nGET /api/v1/users\nAuthorization: Bearer eyJhbGciOiJIUzI1NiIs...\n\n# API key (for server-to-server)\nGET /api/v1/data\nX-API-Key: sk_live_abc123\n```\n\n### Authorization Patterns\n\n```typescript\n// Resource-level: check ownership\napp.get(\"/api/v1/orders/:id\", async (req, res) => {\n  const order = await Order.findById(req.params.id);\n  if (!order) return res.status(404).json({ error: { code: \"not_found\" } });\n  if (order.userId !== req.user.id) return res.status(403).json({ error: { code: \"forbidden\" } });\n  return res.json({ data: order });\n});\n\n// Role-based: check permissions\napp.delete(\"/api/v1/users/:id\", requireRole(\"admin\"), async (req, res) => {\n  await User.delete(req.params.id);\n  return res.status(204).send();\n});\n```\n\n## Rate Limiting\n\n### Headers\n\n```\nHTTP/1.1 200 OK\nX-RateLimit-Limit: 100","sourceCodeStart":298,"sourceCodeEnd":334,"githubUrl":"https://github.com/affaan-m/ECC/blob/d8409a4b0813771235555e32e3d8046a73988bfa/skills/api-design/SKILL.md#L298-L334","documentation":"REST example from the api-design skill: a resource-level handler for GET /api/v1/orders/:id calls Order.findById, and when the lookup returns null it responds 404 with { error: { code: 'not_found' } } before any ownership check runs. Reaching the 404 means the id simply does not match a row (the ownership 403 is a separate, later branch).","triggerScenarios":"GET /api/v1/orders/:id with an id that was never created, was deleted, or has a typo/extra whitespace; an id in a different format than stored (UUID vs integer); a scoped/filtered findById whose filters exclude the row.","commonSituations":"Client caching an id from a previous environment (dev id sent to staging); the record was deleted by another user or a cleanup job; test database not seeded; copy-pasting ids with trailing newlines or mismatched case on case-sensitive stores.","solutions":["Verify the id exists by querying the store directly (or the source system that gave you the id)","Check whether the record was deleted or the id came from a stale cache/another environment","Confirm the id format matches what the API expects (UUID string vs numeric id) with no whitespace or case drift","On the client, treat 404 with code 'not_found' as a terminal condition: clear the cached id / redirect, do not retry"],"exampleFix":"// before - client assumes the order exists and crashes on undefined\nconst order = await (await fetch(`/api/v1/orders/${id}`)).json()\nrender(order.items)\n\n// after - branch on the 404 code\nconst res = await fetch(`/api/v1/orders/${id}`)\nif (res.status === 404) return notFoundScreen()\nconst { data } = await res.json()\nrender(data.items)","handlingStrategy":"validation","validationCode":"// Client: sanity-check the id format before spending a round trip\nconst isUuid = (id: string) =>\n  /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(id.trim())\nif (!isUuid(orderId)) throw new Error(`malformed order id: ${orderId}`)","typeGuard":null,"tryCatchPattern":"const res = await fetch(`/api/v1/orders/${encodeURIComponent(orderId)}`)\nswitch (res.status) {\n  case 200: return await res.json()\n  case 404: return null            // terminal: caller decides (clear cache / show empty state), do not retry\n  case 403: throw new ForbiddenError()\n  default:   throw new Error(`unexpected status ${res.status}`)\n}","preventionTips":["Validate id format (UUID/numeric) client-side before requesting","Treat 404 as a terminal condition, never an automatic retry","Invalidate cached ids when records can be deleted (or TTL them) so stale references die quickly","Keep dev/staging ids separate — never reuse ids captured from another environment"],"tags":["rest","http-404","express","resource-lookup"],"backgroundTag":"resource-not-found","analyzedSha":"d8409a4b0813771235555e32e3d8046a73988bfa","analyzedAt":"2026-08-26T12:15:34.022Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}