DEV Community

Shahar Kedar
Shahar Kedar

Posted on • Updated on

Input Validation

Input validation meme

On the previous chapter I used a boring example for using Zod. It was boring because there was no external input involved. Zod is useful when we need to deal with data, whose shape (and therefore type) is only determined in runtime and the TypeScript compiler can't keep us safe. A very common example is when handling incoming HTTP requests. For example:

const UserSchema = z.object({
  name: z.string(),
  age: z.number(),
  email: z.string().email(),
});
type User = z.infer<typeof UserSchema>;

async function createUser(req: Request, res: Response): Promise<void> {
  const userData: User = UserSchema.parse(req.body);
  const newUser = await saveUser(userData);
  res.json(newUser);
}
Enter fullscreen mode Exit fullscreen mode

We get two main benefits by using Zod:

  1. We can validate our input using Zod's built-in and tested validation logic. The createUser function will fail if the email property contains a random string.
  2. userData is typed. We don't need to use casting (god forbid!) to work with the correct type in our application logic.

Why should I care about input validation?

Well... there are many good reasons but for starters it keeps your code secure, preventing code injection hacks and the like, but it also keeps you code less prone to unusual bugs. I feel like security has been discussed a lot so I'm not going to talk about that here. But the latter reason is as important IMHO.

There are a few questions we should ask ourselves:

Where do we rather catch an error?

I would argue that it's best to catch an error as close as possible to the source of the error. If the code is very simple, that might not be important, but if we run complex logics and/or transactions, catching the error at the beginning might prevent weird or critical bugs related to state inconsistency etc.

What kind of error do we prefer?

Error meme

If you've been working with JavaScript for a while you're probably familiar with the infamous "Uncaught TypeError: Cannot Read Property of Undefined" error. I really hate when that happens! And really it could be easily avoided with Zod and the right schema.

Lets see this in action. First we'll change our HTTP handler to not use Zod and run some basic logic:

async function createUser(req: Request, res: Response): Promise<void> {
  const user: User = req.body;
  processEmail(user);
  res.status(200).end();
}

function processEmail(user: User) {
  if (user.email.split("@")[1].endsWith("gmail.com") {
    doSomethingGoogly(user);
  } else {
    doSomethingElse(user)
  }
}
Enter fullscreen mode Exit fullscreen mode

What kind of error would we get if req.body doesn't contain an email?

TypeError: Cannot read properties of undefined (reading 'split')
Enter fullscreen mode Exit fullscreen mode

Did I already mention that I hate this error? 🤬

What kind of error would we get with Zod?

ZodError: [
  {
    "code": "invalid_type",
    "expected": "string",
    "received": "undefined",
    "path": [
      "email"
    ],
    "message": "Required"
  }
]
Enter fullscreen mode Exit fullscreen mode

Nice!

Summary

Zod becomes useful when you need to validate external input. One very common use case is when handling incoming HTTP requests. Zod is cool because it infers types out of schemas and allows you to use those types in your business logic. Assuming your schema is correct, the TypeScript compiler guarantees that correct input will be handled correctly. No surprises.

Input validation is important because it prevents bugs from happening deep in our code and provides meaningful error messages that's easier to understand and solve.

Next chapter would be on how to sanitize incoming HTTP requests with Zod.

Top comments (2)

Collapse
 
akivaschiff profile image
akivaschiff

This is great! I think the line I loved most was "I would argue that it's best to catch an error as close as possible to the source of the error". You've put in to words a feeling I've had but I've never had a sentence for it and now I do. One thing I found a little complicated with zod is that sometimes the errors it throws aren't very clear. Will you be getting into understanding zod errors?

Collapse
 
shaharke profile image
Shahar Kedar

Absolutely!