Why you should be doing schema validation in React projects

Kolby Sisk
Udacity Eng & Data
Published in
3 min readDec 13, 2021

--

Photo by FLY:D on Unsplash

When developing a client app it’s important to validate the data that comes in. The two most common ways data is inserted into your app is through network requests and forms.

Schema Validation

A schema is a set of rules that define how a data set should be structured. Using a tool like Zod you can define a schema, and then validate if a data set adheres to the schema’s rules.

// Define a schema
const dogSchema = z.object({
id: z.string(),
name: z.string(),
age: z.number().positive(),
});
// Validate using .parse, which throws if it doesn't validate
dogSchema.parse({
id: '1a2b3c',
name: 'Spot',
age: 3,
});

Validating Network Requests

When you make a request to fetch data from a server, you should never assume you’ll know the contents of the data at run-time. You can gain some confidence using GraphQL, but even that doesn’t provide type safety, or more complex validation rules.

There’s a pattern I use for every network request I make to ensure the data being fetched is exactly what my app expects:

import * as z from 'zod';const dogSchema = z.object({
id: z.string(),
name: z.string(),
age: z.number().positive(),
});

type Dog = z.infer<typeof dogSchema>;
const getDog = async (): Dog => {
const response: unknown = await (await fetch('/api/dog')).json();
try{
dogSchema.parse(response);
} catch(error){
// Log & alert error <-- very important!
}
return response as Dog;
}
  1. The fetch response is typed unknown
  2. The response is validated against a schema
  3. Then we safely assert the response as the type we validated and return

One of my favorite features of Zod is inferring types from a schema 🙌
By inferring the type we are reducing our code, but more importantly reducing dependent code. Without inference, every time we need to change the type of Dog we also have to change the schema, and vice versa.

The most important step is ensuring you have logging and alerting set up in your project so these potentially critical errors can be fixed asap. It’s not a matter of if your schema validation will catch an error, but when. You can reduce the chances of a user finding an error by implementing automated e2e testing.

Validating forms

User inputted data is another source of unknown data, and as mentioned previously, schema validation is a great solution for validating unknown data. I use React Hook Form because of the exceptional dev experience, cleaner form implementation, optimal performance, and maybe most importantly: it integrates beautifully with Zod. To integrate the two we simply import the Zod Resolver, and give it a schema.

import * as z from 'zod';
import { zodResolver } from '@hookform/resolvers/zod';
const dogSchema = z.object({
name: z.string(),
age: z.number().positive(),
});

type Dog = z.infer<typeof dogSchema>;

const CreateDogForm: FC = () => {
const { register, handleSubmit, formState: {errors} } = useForm<Dog>({
resolver: zodResolver(dogSchema)
});

const createDog = useCallback((newDog: Dog) => {
dogMutation.mutate(newDog);
}, []);

return (
<form onSubmit={handleSubmit(createDog)}>
<input {...register('name')} />
{errors.name?.message && <p>{errors.name.message}</p>}

<input {...register('age')} type="number" />
{errors.age?.message && <p>{errors.age.message}</p>}

<button>Create<button>
</form>
)
}

When the form is submitted it is validated against the provided schema. If there are validation errors then error messages are rendered.

I’ve found that schemas used for network requests can often be reused for forms, which ultimately results in a very ergonomic solution.

Conclusion

If you’re not using a schema validation tool like Zod to validate the unknown data coming into your app, you’re leaving your app vulnerable to very common and potentially critical errors. Use schema validation in combination with alerting and automated e2e testing to gain confidence you’ll find the errors before your users do. Take it a step further and use Zod with React Hook Form to validate user inputted data, and you’re left with an extremely robust and ergonomic solution.

--

--

Builder of software with a passion for learning. I specialize in web development and user experience design. www.kolbysisk.com