uestion: Coercing FormData values for server-side Zod validation
Hey everyone! I’m using Zod for validation both on the client and server. On the client, validation works perfectly. But when I send the form to a server action using FormData, things fall apart.
Specifically:
The browser correctly sends all form fields as strings, but my server-side schema expects num to be a number:
In my server action, I use createServerValidate() like this:
But since formData.get("num") returns a string, z.number() fails validation.
What’s the proper way to coerce FormData values (like "num") into the correct types before passing them into the schema for server validation? Should I transform formData to a plain object with type coercion first, or is there a built-in/best-practice way of handling this with Zod or createServerValidate?
Thanks in advance!
8 Replies
quickest-silverOP•3mo ago
I have tried the following ofcourse:
though this results in a type error.
something allong the lines of ~standard types are incompatible between these types Type 'Types<{num:unknown}> type unknown is not assignable to type number
fascinating-indigo•3mo ago
Haven't worked with Server-Side, but: TSF doesn't transform the data, you've got to do that yourself.
quickest-silverOP•3mo ago
thanks for your reply? Any idea how i would tranform the data in the server action?
quickest-silverOP•3mo ago
I noticed tin the following example that the result of
validatedData.age
is also a string and not a number; https://tanstack.com/form/latest/docs/framework/react/examples/next-server-actions?path=examples%2Freact%2Fnext-server-actions%2Fsrc%2Fapp%2Faction.tsReact TanStack Form Next Server Actions Example | TanStack Form Docs
An example showing how to implement Next Server Actions in React using TanStack Form.
fascinating-indigo•3mo ago
You'll have to
z.parse
somewhere, not sure where though, the output of it will be the transformer/coerced valuesquickest-silverOP•3mo ago
the weird thing is (or perhaps it's my misunderstanding) that serverValidate takes in formData, so the input values values would always be strings, so I really don't know where I'd do the transform
fascinating-indigo•3mo ago
You should validate the data on the server again as you can't trust the data the client sends you.
You'll need to parse the data again here
This should still be the
z.input
type.
So throw that through z.parse
again and you have the transformer data (z.output
)
Using coerce you should be able to only need one Schema that can handle the incoming values on the client and the serverquickest-silverOP•3mo ago
The problem is that the validation fails.
await serverValidate(formData)
throws a validation error since
and transforming formData before passing it to serverValidate is not allowed, since that would not fit the FormData type
i did find a somewhat sketchy solution; this works, though I feel like this is not the proper way to go: