trails/packages/api/src/errors.ts
Ullrich Schäfer edd2cabf12
DRY up ZodError → FieldError mapping
Five journal API route handlers had the same inline lambda:

    parsed.error.issues.map((i) => ({
      field: i.path.join("."),
      message: i.message,
    }))

Pull it into `zodIssuesToFieldErrors(error)` next to FieldError in
`@trails-cool/api/errors.ts` and re-export it so all five handlers
share the same implementation. The path-flattening rule now lives in
one place, and new routes get it for free.

Public error-response shape is unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 11:45:09 +02:00

38 lines
1 KiB
TypeScript

import { z } from "zod";
export const FieldErrorSchema = z.object({
field: z.string(),
message: z.string(),
});
export const ApiErrorResponseSchema = z.object({
error: z.string(),
code: z.string(),
fields: z.array(FieldErrorSchema).optional(),
});
export type FieldError = z.infer<typeof FieldErrorSchema>;
export type ApiErrorResponse = z.infer<typeof ApiErrorResponseSchema>;
/**
* Map a ZodError's issues to the FieldError[] shape used in API
* validation responses. Keeps the path-flattening rule in one place so
* every route returns validation errors in the same shape.
*/
export function zodIssuesToFieldErrors(error: z.ZodError): FieldError[] {
return error.issues.map((i) => ({
field: i.path.join("."),
message: i.message,
}));
}
/** Standard error codes */
export const ERROR_CODES = {
VALIDATION_ERROR: "VALIDATION_ERROR",
NOT_FOUND: "NOT_FOUND",
UNAUTHORIZED: "UNAUTHORIZED",
FORBIDDEN: "FORBIDDEN",
CONFLICT: "CONFLICT",
RATE_LIMITED: "RATE_LIMITED",
INTERNAL_ERROR: "INTERNAL_ERROR",
} as const;