# Validation with zod Validation your data before it get in to your code is the clean way. - Know actually, what kind of data you gonna get - No some kind of unknown bug when in production ## Why do we need to validate our data? Data that came after validation will be more accurate than the normal data. Data can be manipulated in any way, so validation before any action is a secure choice. ## Why do we use zod? There are some alternatives to Zod to validate your data with [joi](https://joi.dev). You can see a comparation on their [website](https://zod.dev/?id=comparison). We will use Zod for now. Zod can be used with **JavaScript** and **TypeScript**. You can parse the data without doing any validation. ## Installation In this example, we will use Zod in the NodeJS project. We will need [NodeJS](https://nodejs.org). After installing the NodeJS, you can create a node project with the command `npm init -y` in your project folder. The node will generate the project for you. ### Install zod dependency To install Zod dependency, you can run this command: `npm install zod`. ## Schema Zod will need Zod schema to define the data from you. The Zod schema will be **required** by **default**. ```typescript // String schema const stringSchema = z.string(); // Optional const opStringSchema = z.string().optional(); // or const opStringSchema = stringSchema().optional(); // Object const student = z.object({ name: z.string(), age: z.number(), }) ``` We can do more with pre-build validation like Email, URL, etc. ```typescript // Email const emailSchema = z.string().email(); // URL const urlSchema = z.string().url(); // RegEx const regExSchema = z .string() .regex(/^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/); // ``` And there are more than this in their [docs](https://zod.dev/?id=strings) ![String Validation](https://hackmd.io/_uploads/rJHWDunhn.png) ## Custom Schema Match prefers to use custom schema with **TypeScript** rather than **JavaScript**. ```typescript const px = z.custom<`${number}px`>((val) => { return /^\d+px$/.test(val as string); }); type px = z.infer<typeof px>; // `${number}px` px.parse("42px"); // "42px" px.parse("42vw"); // throws; ``` ## Custom Error You can create custom errors too. ```typescript // String const name = z.string({ required_error: "Name is required", invalid_type_error: "Name must be a string", }); // Number z.number().lte(5, { message: "this is too big" }); // lte = less than equal to (<=) ``` ## Validation There are 2 preferred ways to validate data with schema: ### Parse Parse will throw the error if the condition is not satisfied. ```typescript const stringSchema = z.string(); stringSchema.parse("fish"); // => returns "fish" stringSchema.parse(12); // throws error ``` ### SafeParse SafeParse method will return an object with success and data or error. ```typescript const stringSchema = z.string(); stringSchema.safeParse("fish"); // => { success: true; data: 'fish' } stringSchema.safeParse(12); // => { success: false; error: ZodError } ``` ## Transform Transform data after parsing. ```typescript const stringToNumber = z.string().transform((val) => val.length); stringToNumber.parse("string"); // => 6 ``` ## Refine Customize your validation with the `refine` method from Zod. ```typescript const myString = z.string().refine((val) => val.length <= 255, { message: "String can't be more than 255 characters", }); ``` **NOTE**: From the [document](https://zod.dev/?id=refine), Zod said: > ⚠ Refinement functions should not throw. Instead they should return a falsy value to signal failure. ## Asynchronous Zod also provides you with async functions. **An Example** ```typescript const stringSchema = z.string().refine(async (val) => val.length <= 8); await stringSchema.parseAsync("hello"); // => returns "hello" await stringSchema.parseAsync("hello world"); // => throws error ``` --- ## Bonus This is just the surface of the Zod library. If you want more information, you can check out their [docs](https://zod.dev/).