Skip to content

Instantly share code, notes, and snippets.

@JTRNS
Created April 7, 2024 19:21
Show Gist options
  • Save JTRNS/63e56fa398b17bc7519c422caa510dbe to your computer and use it in GitHub Desktop.
Save JTRNS/63e56fa398b17bc7519c422caa510dbe to your computer and use it in GitHub Desktop.
Remix Form Actions Helper
import type { ActionFunctionArgs, ActionFunction } from "@remix-run/node";
import type { AnyZodObject, z } from "zod"
export type FormActionHandler<T extends AnyZodObject> = (data: z.infer<T>, args: ActionFunctionArgs) => Promise<Response | null>
export type FormAction<T extends AnyZodObject> = {
schema: T
} & {
handler: FormActionHandler<T>
}
export function createFormActions<T extends AnyZodObject>(actions: Record<string, FormAction<T>>): ActionFunction {
async function handleFormActions(args: ActionFunctionArgs) {
const req = args.request.clone();
// check the method is post otherwise throw 405
if (req.method !== "POST") {
throw new Response("Method Not Allowed", { status: 405 });
}
const contentType = req.headers.get("Content-Type");
if (!contentType || contentType.toLowerCase() !== "application/x-www-form-urlencoded") {
throw new Response("Unsupported Media Type", { status: 415 });
}
const formdata = await req.formData();
// ensure that formdata has an "_action" property and that its value is a key in actions object
const actionKey = formdata.get("_action")?.toString();
if (!actionKey || !actions[actionKey]) {
throw new Response("Bad Request", { status: 400 });
}
const action = actions[actionKey];
// remove "_action" from formdata
formdata.delete("_action");
const data = action.schema.parse(Object.fromEntries(formdata));
return action.handler(data, args)
}
return handleFormActions;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment