unify api error response shape
Created by: jedmund
Summary
Architecture audit A-1 — collapse the two competing API error shapes into one.
Every errorResponse() call now emits { error: { code, message, details? } } where code is a symbolic name derived from the HTTP status (e.g. 401 → UNAUTHORIZED, 404 → NOT_FOUND, 500 → INTERNAL_ERROR). Clients get a consistent, self-describing shape and a stable place to attach validation details.
-
New:
src/lib/server/error-codes.ts— status → code map +codeForStatus()helper -
Updated:
errorResponse(message, status, details?)emits the structured shape. Signature preserved — all ~300 route-side callers keep working unchanged. -
Updated:
hooks.server.tsunauth response aligned to the same shape. -
Updated: 7 admin client fetch consumers now read
errorData.error?.message. Three of them were reading.erroras a string (will-break path). Four were silently broken (reading top-level.messagethat the old shape didn't emit either) — these now actually surface error messages.
Public pages that read data.error from +page.server.ts loaders are unaffected (loader-set strings, not API responses). Tags routes' bespoke json({error: {code, message, field, details}}) calls already match the new shape. Success response bodies unchanged.
Test plan
-
pnpm check— baseline 116 errors / 9 warnings, no new ones -
curl -IunauthenticatedGET /api/admin/media-stats→ body is{"error":{"code":"UNAUTHORIZED","message":"Unauthorized"}} -
POST /api/postswith invalid JSON →{"error":{"code":"BAD_REQUEST","message":"..."}} -
Delete an album from the admin UI while logged out → status message shows "Unauthorized" (not undefined) -
Upload a file that fails server validation via ImageUploader→ toast shows the actual error message -
Tag with reserved name → admin TagInputstill shows theTAG_NAME_RESERVEDmessage (tags route keeps its bespoke shape)