Skip to content

Instantly share code, notes, and snippets.

@aq1
Last active November 22, 2023 21:42
Show Gist options
  • Save aq1/4b57ed9d5cc2d79c449763e92e2507ff to your computer and use it in GitHub Desktop.
Save aq1/4b57ed9d5cc2d79c449763e92e2507ff to your computer and use it in GitHub Desktop.
Next Server Action with generic Zod validator
"use server";
// inspired by tRPC
import z from "zod";
const action = <T>(schema: z.Schema<T>) => {
return {
do:
<R>(callback: ({ data }: { data: T }) => Promise<R>) =>
async (formData: FormData) => {
const res = schema.safeParse(Object.fromEntries(formData.entries()));
if (res.success) {
try {
return {
success: true,
out: await callback({ data: res.data }),
};
} catch (error) {
return {
success: false,
error: "Unexpected error",
};
}
} else {
return {
success: false,
error: res.error.format(),
};
}
},
};
};
const exampleSchema = z.object({
name: z.string(),
});
export const exampleAction = action(exampleSchema).do(async ({ data }) => {
const { name } = data;
return {
message: `Hello ${name}`,
};
});
"use client";
import { exampleAction } from "~/app/actions/updateMe";
export const Form = () => {
const update = async (formData: FormData) => {
const result = await exampleAction(formData);
if (!result.success) {
alert(JSON.stringify(result.error));
} else {
alert(result.out?.message);
}
};
return (
<form action={update}>
<div className="flex w-32 flex-col">
<input type="text" name="name" />
<button>Save</button>
</div>
</form>
);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment