Skip to content
This repository has been archived by the owner on Sep 27, 2023. It is now read-only.

How about FormData? #25

Open
verheyenkoen opened this issue May 9, 2023 · 9 comments
Open

How about FormData? #25

verheyenkoen opened this issue May 9, 2023 · 9 comments

Comments

@verheyenkoen
Copy link

I guess this doesn't work out-of-the-box with FormData (as zod doesn't really have a built-in way to work with FormData)?

Also, if it did and I wanted to create a regular form with a server action that posts the form data via Next.js, would there ever be a way to catch validation errors and display those cleanly within your form? Currently the docs suggest you can end that scenario only with redirect, revalidatePath and revalidateTag.

I know you can do this:

<form onSubmit={async (e) => {
   e.preventDefault();
   const myData = ...
   const response = await myServerAction(myData);
   // Deal with validation errors here
}}

but then we're spaghetticoding again, which the whole action={myServerAction} is trying to solve...

@chungweileong94
Copy link

For form data, this is what you are looking for, https://www.npmjs.com/package/zod-form-data.
I'm currently looking into building something like remix-validated-form, which is probably something we can refer to.

@verheyenkoen
Copy link
Author

I know there's zod extension packages for FormData, but I guess you can't just go and use those with zact, or am I wrong there?

@verheyenkoen
Copy link
Author

verheyenkoen commented May 9, 2023

Made a quick POC now and turns out I can use zod-form-data out of the box for that but a few problems remain:

  • The validated action infers the zod/zfd schema type and Typescript yells when you pass it FormData.

    Type  FormData  is missing the following properties from type '{ name: string; age: number; }': name, age

  • Inside the server action I get the FormData object and not the parsed data, even though Typescript infers this as the input type.

  • Other problem (probably unrelated to FormData) is that the ZodValidationError thrown in case of invalid data loses its' issues bag of data to break down errors on a field level. But you do get the error message through to the client though.

@chungweileong94
Copy link

  • The validated action infers the zod/zfd schema type and Typescript yells when you pass it FormData.

Yeah, there's a problem with the input type, which I already created PR #19 to address that. As of now, you can patch the package locally to workaround.

@chungweileong94
Copy link

chungweileong94 commented May 9, 2023

  • Other problem (probably unrelated to FormData) is that the ZodValidationError thrown in case of invalid data loses its' issues bag of data to break down errors on a field level. But you do get the error message through to the client though.

Yeah, that's something I'm trying to figure out. The simplest solution I can think of is to have an option to prevent error throwing, like zact.(z.string(), { throwValidationError: false }), but I don't really like that DX personally.

Or even better, we can borrow something from trpc

zact
  .input(z.string(), { throwValidationError: false })
  .action((input) => { })

@sam3d
Copy link

sam3d commented Sep 19, 2023

Aren't server actions just functions? I'm unsure why Zod's primitives for this aren't sufficient:

"use server";

export const action = z
  .function()
  .args(z.object({ hello: z.boolean() }))
  .implement(async (data) => {
    console.log("Server", data);
  });

@chungweileong94
Copy link

Aren't server actions just functions? I'm unsure why Zod's primitives for this aren't sufficient

You are actually correct, Zod alone is sufficient enough if you only want to validate the input data.
But it wasn't enough if you want to catch the invalid input and display the error on to client-side.

@verheyenkoen
Copy link
Author

verheyenkoen commented Sep 19, 2023

I resorted to this setup with react-hook-form as an intermediary with Zod validation. Basically validation is first done on the client, and the data is sent as an object instead of FormData to the sever where you can reuse the same Zod schema for server-side validation. Whatever is still invalid at that point has been messed with by the end user so you can basically throw dirty errors that are handled by an error boundary (or Next.js error pages) from that point I guess...

Tutorial: https://www.youtube.com/watch?v=h3w9tQoXx5I&t=1s&pp=ygUSem9kIHNlcnZlciBhY3Rpb25z

@chungweileong94
Copy link

@verheyenkoen Yeah, having the client-side validation works too, I personally use it myself. But when it comes to progressive enhancement, they are not really an option.

I personally don't really enjoy having a form library and validation library bundle in client code, as they add quite a bit to the bundle size, even for a simple form. I always wanted to do something similar to remix-validated-form, validation on server-side, but it just not possible with NextJS yet. I heard they (React/Vercel Team) are planning something in the near future, something similar to the experimental useOptimistic & useFormStatus.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants