Use Zod for All Form Validation

Kent C. Dodds
Kent C. Dodds

In this video, Kent takes a detailed look at transforming form data into sessions using Zod and Conform. He addresses a specific challenge in handling optional login sessions and presents a solution that integrates a .transform step. This asynchronous function validates and converts the username and password into a session, seamlessly fitting into existing Zod schema validation. By the end of the video, Kent ensures that the parsed data is completely validated and ready to use, eliminating the need for additional validation steps. The video aims to offer valuable insights, whether the viewer is a Zod and Conform user or not.


00:00 Hey, I want to show you something really quick. So we've got this action right here. This is part of our login. So the user enters their username and password. We've got this Zod object schema for a username and password.

00:11 We also have a redirect to and a remember. And so with this, we are parsing it using Conform's parse utility, which will take this form data and turn it into this submission object. That submission object has a value, and then we can get the username and password, and then we can log the user in and get a session and all of that stuff. So we've got a little bit of an issue here that I want to talk about, and that is this login can optionally return a session, and the reason for that is it's going to verify the user's password, and if that password is incorrect, or maybe the username doesn't exist or something, then we're not going to get a user back. So we return null.

00:49 Otherwise, we create the session and return that session. So what's interesting about this is we already have a bunch of logic around validating the username and password in the redirect to and remember as part of this form schema. And down inside of our UI, we're using that to generate HTML attributes for constraints, as well as validating things in JavaScript so we don't have to make a network request just to tell them that their username is too short or something like that. And then we have these errors that are propagated to our UI, so we can send those errors to the UI and it looks nice. But now we have another error right here.

01:29 What if they've entered the wrong username or password and so we don't have a session. Well, by the time we get here, we've already skipped the part where we're sending this JSON response back. So instead of throwing an error, I guess we could return another JSON response with the status of error and the submission, But then we'd have to somehow add this additional error message. And it just doesn't feel right. I kind of like being able to say, hey, by the time it gets past this parsing step, then we know that everything has been validated, including the fact that the username and password is correct.

02:04 And so what we can do is we either add a super refine if we just want to do some validation, or we add a transform to transform our username and password into a session, which is what we want to do. Now, we can't just do that on this Zod schema because this is also used in our UI and we can't create a session for the user as part of that process. That just doesn't make any sense. Like, we don't have the ability to make a session in the client. This has to happen on the server.

02:33 So that's why in our action, we're gonna add a .transform, and this is gonna get, it's gonna be async, because we need to create the session. And we're gonna take our data, and with that, then we can do this step, which is basically, essentially what we're doing is we're converting or transforming the username and password that we get from that form submission into a session. So here we'll just pass that data along or we can say data.username and the password is data.password. And that will create us a session and instead of throwing an error, we can use the context object that we get as part of the arguments here. So we get our context And then we can take that context and add an issue where the code is a z.issue, what is it, z.issuecode.custom.

03:24 So this is a custom issue and then the message is invalid username or password. And then we return z.never which is basically says, hey, we got to this transform step and the data is wrong. So the return value of this parsed data should be never. It is not parsed properly. We don't know what it is, but it's not right.

03:46 So with that then, I can return our session along with the data. And so now we've transformed that username and password into the session. And so we can just grab the session right here. And the session will absolutely be a value. So we can just reuse all of the existing stuff that we have for our validation and all of that will continue to work as it did before because we're processing all of the what the user has submitted to us as part of this parsing process.

04:18 So we can just hook into the existing validation that we have with our Zod schema, which I just think is awesome. And I'm really big fan of this approach to taking your form data, validating it, transforming it, super refining it, all of this stuff. And once we get past this parsing stage, the data that we have on the other side should be 100% ready to go. Like completely validated, transform into what it needs to be, all of that stuff. And we don't need to do any additional validation after this point.

04:48 And so that way we just have one place that says, if there was any error at all, let's send it back to the UI. And I do, yeah, big fan of that, big fan of Zod. I hope that helps you if you're not using Conform or Zod. Hopefully at least the concept here makes sense to you and helps you in the work that you're doing. See ya!

More Tips