What is Schema validation and why is it important

Client-Server applications whether web or mobile deal with tons of data transfer happening between server and the client.

What is Schema validation and why is it important

Client-Server applications whether web or mobile deal with tons of data transfer happening between server and the client. And in situations where the structure of the data is going through lots of changes it becomes pain for the client applications to deal with these changes and keep the applications working properly. But how do we make sure that the structure is consistent and changes made to the data structure are properly communicated and taken care of at both ends. This is where schema validation comes into play.

Schema is a blue print (An agreement between server and client on how the data will look like) of the data that will flow between server and the client. When the data is transferred from a server to a client or vice-versa, both sides can validate this data whether it conforms to the schema or not. This will make sure client application or server application will not break because of inconsistent data.

Talking specifically about Node.js applications or JavaScript based client side applications, we have a few libraries available which help doing the schema validation. Two most popular libraries include Zod and Yup. We will mostly be talking about Zod for the rest of this article.

Now you might be thinking why do I need another library to validate the data when I already have TypeScript to check all the inputs. Well! there is a difference. TypeScript doesn't help with the schema validation it only provides type safety during development time. It doesn't help in run-time as it gets transpiled into JavaScript before shipping. Schema validation happens in run-time environment.

A simple example of schema definition and validation using Zod

// Create an schema

const carSchema = z.object({
  id: z.string(),
  name: z.string(),
  make: z.string(),
  year: z.number().positive(),
});

// Validate data against schema using parse or safeParse methods.

carSchema.parse({
  id: '1a2b3c',
  name: 'X4',
  make: 'BMW',
  year: 2022
});

If the data does not conform to the schema, the parse method will throw an error. In most cases we don't want to throw an error and break the application, that's where safeParse method is used.

safeParse method doesn't throw error during the schema validation even if validation fails. It returns an object with parsing information. There is tons of information available in this object but you might only be interested in whether the validation was successful or not ? You can use a property called success for this. In case the validation passed success will be true and it will be false otherwise.

You might be thinking Zod is good, let's just drop the TypeScript and use Zod. Well! no, you still need the type validation during development process. But then I am duplicating the same thing twice. I need to write a schema and a type for each entity in my application which is redundant. Well Zod was written this problem in mind. So it gives you the best experience you can have with both TypeScript and Zod. For example you wouldn't need to write types for the same entity instead you can just infer it from schema like this.

type Car = z.infer<typeof carSchema>;

A complete example using React.js would look something like this.

import React, { useEffect } from "react";
import { z } from "zod";

const carSchema = z.object({
  id: z.string(),
  name: z.string(),
  make: z.string(),
  year: z.number().positive(),
});

type Car = z.infer<typeof carSchema>;

const CarDetails = () => {
  const [car, setCar] = React.useState<Car>(null);

  useEffect(() => {
    fetch("https://api.example.com/cars/123")
      .then((response) => response.json())
      .then((data: unknown) => {
        const car = carSchema.safeParse(data);
        if (!car.success) {
          throw new Error("Invalid car data");
        }
        setCar(car.data);
      });
  }, []);

  return (
    <>
      {!car && <p>Loading...</p>}
      {car && (
        <div>
          <h1>Car Details</h1>
          <p>{car.name}</p>
          <p>{car.make}</p>
          <p>{car.year}</p>
        </div>
      )}
    </>
  );
};

export default CarDetails;

There is a lot more to Zod then schema validation. Such as form validation.

Complete documentation of Zod and more information about schema and form validation is available on their official website linked below.

TypeScript-first schema validation with static type inference
TypeScript-first schema validation with static type inference
GitHub - colinhacks/zod: TypeScript-first schema validation with static type inference
TypeScript-first schema validation with static type inference - colinhacks/zod
Liked it ?

Read more