Skip to content

Instantly share code, notes, and snippets.

@imaginamundo
Created April 10, 2026 14:43
Show Gist options
  • Select an option

  • Save imaginamundo/9e48d6381dc40fbb372c901d3f3ad79a to your computer and use it in GitHub Desktop.

Select an option

Save imaginamundo/9e48d6381dc40fbb372c901d3f3ad79a to your computer and use it in GitHub Desktop.
Parse form schema using zod
import { z } from "astro/zod";
export function formDataToObject(
formData: FormData,
): Record<string, FormDataEntryValue | FormDataEntryValue[]> {
const obj = Object.create(null) as Record<string, FormDataEntryValue | FormDataEntryValue[]>;
for (const [key, value] of formData.entries()) {
if (Object.hasOwn(obj, key)) {
const currentValue = obj[key];
if (!Array.isArray(currentValue)) {
obj[key] = [currentValue, value];
} else {
currentValue.push(value);
}
} else {
obj[key] = value;
}
}
return obj;
}
export function parseSchema<T extends z.ZodTypeAny>(input: FormData, schema: T) {
const fields = formDataToObject(input);
const validation = schema.safeParse(fields);
type InferedType = z.infer<T>;
if (!validation.success) {
const fieldErrors: Partial<Record<keyof InferedType, string>> = {};
for (const issue of validation.error.issues) {
const path = String(issue.path[0]) as keyof InferedType;
if (path && !fieldErrors[path]) {
fieldErrors[path] = issue.message;
}
}
return {
success: false as const,
fields: fields as Partial<InferedType>,
fieldErrors,
};
}
return {
success: true as const,
fields: validation.data as InferedType,
fieldErrors: null,
};
}
@imaginamundo
Copy link
Copy Markdown
Author

Example:

import { defineAction } from "astro:actions";
import { z } from "astro/zod";
import { parseSchema } from "@utils/parseSchema";

const UploadImageSchema = z.object({
	image: z.instanceof(File),
	description: z.string().max(500, "Descrição muito longa.").optional(),
});

export const uploadImage = defineAction({
	accept: "form",
	handler: async (input: FormData, context, session) => {
		const { fields, fieldErrors, success } = parseSchema(input, UploadImageSchema);
		if (!success) {
			// ...everything wrong with the Schema on fieldErrors
			return { success: false as const, error: "Dados inválidos." }
		};

		// ...logic with fields typed when success
	},
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment