mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-03-21 18:04:39 -05:00
41 lines
1.1 KiB
TypeScript
41 lines
1.1 KiB
TypeScript
import type { z } from "zod";
|
|
import { formDataToObject } from "~/utils/remix.server";
|
|
|
|
export type ParseResult<T> =
|
|
| { success: true; data: T }
|
|
| { success: false; fieldErrors: Record<string, string> };
|
|
|
|
/**
|
|
* Parses request body against a Zod schema.
|
|
* Handles both JSON (SendouForm) and form data (FormWithConfirm) based on Content-Type.
|
|
* Returns parsed data on success, or field-level errors on validation failure.
|
|
*/
|
|
export async function parseFormData<T extends z.ZodTypeAny>({
|
|
request,
|
|
schema,
|
|
}: {
|
|
request: Request;
|
|
schema: T;
|
|
}): Promise<ParseResult<z.infer<T>>> {
|
|
const data =
|
|
request.headers.get("Content-Type") === "application/json"
|
|
? await request.json()
|
|
: formDataToObject(await request.formData());
|
|
|
|
const result = await schema.safeParseAsync(data);
|
|
|
|
if (result.success) {
|
|
return { success: true, data: result.data };
|
|
}
|
|
|
|
const fieldErrors: Record<string, string> = {};
|
|
for (const issue of result.error.issues) {
|
|
const path = issue.path.join(".");
|
|
if (path && !fieldErrors[path]) {
|
|
fieldErrors[path] = issue.message;
|
|
}
|
|
}
|
|
|
|
return { success: false, fieldErrors };
|
|
}
|