mirror of
https://github.com/saltbo/zpan.git
synced 2026-08-30 17:50:07 +08:00
8abca2f88c
Collapse the two error conventions (string-reason `{ok:false,reason}` outcomes
and thrown domain-error classes) onto one. Usecases now produce typed `AppError`
values via factories (`notFound()`/`quotaExceeded()`/`featureBlocked()`/…);
handlers `throw result.error`; and `jsonError` (renamed from `renderError`) is the
single place that renders any error to an AIP-193 body + access-log line, in
`app.onError`/accessLog.
Why: the previous setup had a string→code mapping (`outcomeError` + the `OUTCOME`
table) living in parallel with a type→code mapping (`mapDomainError`), plus inline
`apiError(c, <status>, …)` calls that hand-wrote the status at every site — exactly
the drift that left the same `quota_exceeded` at 400 in one handler and 422 in the
rest. Now the status/reason live once, in the factory.
- Add `server/usecases/ports/app-error.ts`: `AppError` + factories. Status/reason
are baked in per factory, so no usecase or handler writes an HTTP code or a
magic-string reason. `AppError` also carries optional response headers
(`Retry-After`) via a `rateLimited()` factory.
- Delete `apiError`, `outcomeError`, the `OUTCOME` table, and the dead `ApiError`
class. The 67 inline guard/middleware `apiError` sites became `throw <factory>()`.
- Control-flow outcomes a handler branches on (not just renders) stay discriminated
reasons (e.g. `deleteObject` `not_trashed`); internal shared sub-usecases
(traffic-metering, licensing internals) keep string reasons, mapped at the boundary.
- Regenerate the Go OpenAPI client (saveShare gained a 422 response).
BREAKING CHANGE: POST /shares/{token}/objects quota rejection now returns 422
(was an inconsistent 400); every other quota path already returned 422.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
24 lines
1.1 KiB
TypeScript
24 lines
1.1 KiB
TypeScript
import type { z } from '@hono/zod-openapi'
|
|
import { errorResponseSchema } from '@shared/schemas'
|
|
|
|
// Shared OpenAPI route helpers used by every resource router. Generic over the
|
|
// schema so its precise type reaches `createRoute`: that types `c.req.valid(...)`
|
|
// on the request side and strictly checks the handler's `c.json(...)` on the
|
|
// response side. A widened `z.ZodType` would erase both — and silently disable
|
|
// response checking, which is how schemas drift from what handlers actually
|
|
// return.
|
|
|
|
export const jsonContent = <T extends z.ZodType>(schema: T, description: string) => ({
|
|
content: { 'application/json': { schema } },
|
|
description,
|
|
})
|
|
|
|
export const jsonBody = <T extends z.ZodType>(schema: T) => ({
|
|
body: { content: { 'application/json': { schema } }, required: true },
|
|
})
|
|
|
|
// A route response carrying the shared AIP-193 `Error` envelope. Handlers and
|
|
// usecases produce errors as `AppError` values that `app.onError` renders via
|
|
// `jsonError`; this just documents the response shape in the OpenAPI document.
|
|
export const errorResponse = (description: string) => jsonContent(errorResponseSchema, description)
|