mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-08 12:32:43 +00:00
refactor(api): extract buildJsonErrorResponse from apiError and returnAllZodIssues
The W2 `returnAllZodIssues` helper duplicated the meta/headers handling
from `apiError`: same `{headers, ...rest}` destructure, same `metaKeys`
length check, same `...(headers ? {headers} : {})` spread on the
constructor. Six lines that drift the moment one helper gains a feature
(e.g. an `errorId` autoinject for Sentry) the other doesn't.
Extract the shared body into `buildJsonErrorResponse(body, status,
meta)`. Both `apiError` and `returnAllZodIssues` collapse to one-line
constructions of the resource-specific body shape. Wire shape is
byte-identical — the 7-case `api-response-zod` suite and every
downstream `apiError` consumer still see the same envelopes.
This commit is contained in:
1 parent
a5176f4be9
commit
d2adf265e4
1 file changed
+36
-29
+36
-29
@@ -44,23 +44,29 @@ export function sanitiseZodIssues(
|
||||
}));
|
||||
}
|
||||
|
||||
export function returnAllZodIssues(
|
||||
error: ZodError,
|
||||
status: number = 422,
|
||||
meta?: {
|
||||
errorCode?: string;
|
||||
headers?: Record<string, string>;
|
||||
} & Record<string, unknown>,
|
||||
type ErrorMeta = {
|
||||
errorCode?: string;
|
||||
headers?: Record<string, string>;
|
||||
} & Record<string, unknown>;
|
||||
|
||||
/**
|
||||
* Shared builder for every `{ data: null, error, ... }` JSON envelope.
|
||||
* Strips `headers` from the meta passthrough (it lands on the
|
||||
* NextResponse constructor, not in the JSON body) and omits the `meta`
|
||||
* key entirely when no non-header fields remain — so the unchanged
|
||||
* `{ data: null, error: <string> }` envelope still serialises byte-
|
||||
* identically when the caller passes no extras.
|
||||
*/
|
||||
function buildJsonErrorResponse(
|
||||
body: Record<string, unknown>,
|
||||
status: number,
|
||||
meta: ErrorMeta | undefined,
|
||||
): NextResponse {
|
||||
const { headers, ...rest } = meta ?? {};
|
||||
const metaKeys = Object.keys(rest);
|
||||
return NextResponse.json(
|
||||
{
|
||||
data: null,
|
||||
error: "Validation failed",
|
||||
details: {
|
||||
issues: sanitiseZodIssues(error.issues),
|
||||
},
|
||||
...body,
|
||||
...(metaKeys.length > 0 ? { meta: rest } : {}),
|
||||
},
|
||||
{
|
||||
@@ -70,6 +76,22 @@ export function returnAllZodIssues(
|
||||
);
|
||||
}
|
||||
|
||||
export function returnAllZodIssues(
|
||||
error: ZodError,
|
||||
status: number = 422,
|
||||
meta?: ErrorMeta,
|
||||
): NextResponse {
|
||||
return buildJsonErrorResponse(
|
||||
{
|
||||
data: null,
|
||||
error: "Validation failed",
|
||||
details: { issues: sanitiseZodIssues(error.issues) },
|
||||
},
|
||||
status,
|
||||
meta,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* `meta` is additive — clients that ignore it see the unchanged
|
||||
* `{ data: null, error: <string> }` envelope. New callers can pass
|
||||
@@ -86,24 +108,9 @@ export function returnAllZodIssues(
|
||||
export function apiError(
|
||||
message: string,
|
||||
status = 400,
|
||||
meta?: {
|
||||
errorCode?: string;
|
||||
headers?: Record<string, string>;
|
||||
} & Record<string, unknown>,
|
||||
meta?: ErrorMeta,
|
||||
) {
|
||||
const { headers, ...rest } = meta ?? {};
|
||||
const metaKeys = Object.keys(rest);
|
||||
return NextResponse.json(
|
||||
{
|
||||
data: null,
|
||||
error: message,
|
||||
...(metaKeys.length > 0 ? { meta: rest } : {}),
|
||||
},
|
||||
{
|
||||
status,
|
||||
...(headers ? { headers } : {}),
|
||||
},
|
||||
);
|
||||
return buildJsonErrorResponse({ data: null, error: message }, status, meta);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in new issue
Block a user