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>
38 lines
1 KiB
TypeScript
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;
|