12 septembre 2024
Comment utiliser Zod pour valider des données en TypeScript
7 minutes de lecture
La donnée est au cœur de la plupart des applications. Que ce soit pour un formulaire, une API ou une base de données, il est essentiel de s'assurer que les données que vous manipulez sont valides. En TypeScript, il est possible de définir des types pour vos données, mais cela ne garantit pas que les données que vous recevez sont correctes. C'est là qu'interviennent les validateurs. Dans cet article, nous allons voir comment utiliser Zod.
Qu'est-ce que Zod ?
Zod est une bibliothèque de validation de données pour TypeScript. Elle permet de définir des schémas de validation pour vos données et de les valider. Zod est conçu pour être simple à utiliser et à comprendre, tout en étant puissant et flexible.
Pourquoi utiliser Zod ?
Dans les applications de l'écosystème javascript modernes, TypeScript est devenu un choix populaire pour la gestion des types. Cependant le typage des données saisies par l'utilisateur ou extraite d'une base de données reste déclaratif. Typescript ne peut pas garantir que les données reçues respectent les types définis. En validant les données, Zod permet de s'assurer que les données reçues sont correctes, de faire un typage fort, de réduire les erreurs dans votre application et augmenter la sécurité en évitant de traiter des données incorrectes.
Que ce soit pour valider des données provenant d'un formulaire, de searchParams
, d'une API ou directement d'une base de données, les validateurs sont un outil essentiel pour garantir la qualité des données que vous manipulez.
Concepts clés
Avant de commencer à utiliser Zod, il est important de comprendre quelques concepts clés :
- Schéma : Un schéma est une définition de la structure des données que vous souhaitez valider. Il peut s'agir d'un objet, d'un tableau, d'une chaîne de caractères, etc.
- Parser : Un parser est une fonction qui prend une valeur en entrée et retourne un objet d'erreurs s'il y a des erreurs de validation ou la valeur validée et/ou modifiée si la validation est réussie.
- Type : Un type est une représentation des données que vous souhaitez valider. Il peut s'agir d'un type primitif comme une chaîne de caractères ou un nombre, ou d'un type plus complexe comme un objet ou un tableau.
Installation
Pour commencer à utiliser Zod, vous devez l'installer dans votre projet. Vous pouvez le faire en exécutant la commande suivante :
npm install zod
ou
yarn add zod
Schémas
Les schémas sont les briques de base de Zod. Ils définissent la structure des données que vous souhaitez valider. Dans cette partie, nous allons voir comment définir des schémas avec Zod.
Types primitifs
Zod fournit de méthodes pour représenter l'ensemble des primitives JavaScript dans les schémas. Voici quelques exemples :
import z from 'zod'
const stringSchema = z.string()
const numberSchema = z.number()
const booleanSchema = z.boolean()
const objectSchema = z.object({ value: z.null() })
Coerce
Il est possible de contraindre des valeurs à des types spécifiques en utilisant la méthode coerce
. Par exemple, vous pouvez contraindre une valeur à une chaîne de caractères :
const coerceStringSchema = z.coerce.string()
Dans ce cas là Zod va caster la valeur en chaîne de caractères si elle ne l'est pas déjà.
Décorateurs
Pour aller plus loin, Zod permet de définir des décorateurs
pour les types primitifs. Par exemple, vous pouvez définir un schéma pour un nombre entier positif :
const positiveNumberSchema = z.number().positive()
On retrouvera dans cette catégorie des méthodes comme min
, max
, email
, url
, uuid
, etc.
Ou même des méthodes pour rendre des champs optionnels ou obligatoires :
const optionalStringSchema = z.string().optional()
const requiredStringSchema = z.string().nonempty()
Il est possible de chaîner les méthodes pour définir des schémas plus complexes :
const nonEmptyStringSchema = z.string().nonempty().min(3)
Pour faire une validation avancée sur un champ, il est possible d'utiliser la méthode refine
qui permet de définir une fonction de validation personnalisée :
const customStringSchema = z.string().refine((value) => value.length > 3, {
message: 'La chaîne de caractères doit contenir au moins 3 caractères',
})
Transformations
Il est possible de transformer les valeurs validées en utilisant la méthode transform
. Par exemple, vous pouvez transformer une chaîne de caractères en majuscules :
const uppercaseStringSchema = z.string().transform((value) => value.toUpperCase())
Cette méthode peut donner lieu à un changement de type de la valeur. En chaînant les méthodes
transform
et validation d'un type, il est possible de transformer une valeur en un autre type.
Il est possible de définir des valeurs par défaut pour les schémas en utilisant la méthode default
. Par exemple, vous pouvez définir une valeur par défaut pour un nombre :
const defaultNumberSchema = z.number().default(42)
Marge d'acceptation
Il est possible de définir une marge d'acceptation pour les schémas portant sur le type object
en utilisant les méthodes partial
, strict
, passthrough
et strip
(par défaut). Par exemple, vous pouvez définir un schéma pour un objet avec des champs optionnels :
const userSchema = z
.object({
name: z.string(),
age: z.number().optional(),
})
.partial()
Récursivité
Il est possible de définir des schémas récursifs en utilisant la méthode lazy
. Pour cela il faut utiliser l'approche type first. Par exemple, vous pouvez définir un schéma pour une liste d'entiers :
type User = {
name: string
age?: number
contacts?: User[]
}
const userSchema: z.ZodType<User> = z.object({
name: z.string(),
age: z.number().optional(),
contacts: z.lazy(() => z.array(userSchema)),
})
Fusion de schémas
Exactement comme en Typescript, il arrive parfois d'avoir besoin de fusionner plusieurs schémas. Zod permet de le faire en utilisant les méthodes merge
, and
, or
ou extend
.
Attention, dans le cas de la méthode
and
, les schémas doivent être compatibles. Dans le cas contraire, le schéma sera invalide.
Dans les cas de extend
et merge
, les champs surchargés seront remplacés par les nouveaux champs.
const userSchema = z.object({
name: z.string(),
age: z.number().optional(),
})
const extendedUserSchema = userSchema.extend({
street: z.string(),
city: z.string(),
})
Analyse d'objet
La méthode parse
Maintenant que nous avons vu comment définir des schémas avec Zod, nous allons voir comment les utiliser pour valider des données. Dans cette partie, nous allons voir comment analyser un objet avec Zod.
L'ensemble de la validation se fait principalement en utilisant la méthode parse
sur un schéma. Par exemple, vous pouvez analyser un objet avec un schéma :
const userSchema = z.object({
name: z.string(),
age: z.number().optional(),
})
const user = userSchema.parse({
name: 'John Doe',
age: 42,
})
Si les données ne respectent pas le schéma, Zod renverra une erreur en levant une exception :
try {
const user = userSchema.parse({
name: 'John Doe',
age: '42',
})
} catch (error) {
console.error(error.errors)
}
La méthode safeParse
Pour éviter de lever une exception, il est possible d'utiliser la méthode safeParse
qui retourne un objet d'erreurs si la validation échoue :
const result = userSchema.safeParse({
name: 'John Doe',
age: '42',
})
if (!result.success) {
console.error(result.error.errors)
}
L'inférence de type
Inférer le type d'un schéma
Zod permet d'inférer les types des schémas définis. Par exemple, vous pouvez inférer le type d'un schéma :
const userSchema = z.object({
name: z.string(),
age: z.number().optional(),
})
type User = z.infer<typeof userSchema>
Ainsi, vous pourrez utiliser le type User
pour typer vos données, ça s'apparente à une forme de schema first
.
Inférer un schéma à partir d'un type
Dans le cas où vous avez besoin d'appliquer un type déjà existant à un schéma Zod, il est possible d'utiliser l'inférence de type pour le faire :
type User = {
name: string
age?: number
}
const userSchema: z.ZodType<User> = z.object({
name: z.string(),
age: z.number().optional(),
})
const user = userSchema.parse({
name: 'John Doe',
age: 42,
})
// user est de type User
Cette approche s'apparente à une forme de type first
. De cette manière, vous pourrez constater que le type User
est bien respecté par le schéma userSchema
.
Autres validateurs
Dans cet article, nous avons parlé des validateurs à travers Zod, mais il existe d'autres bibliothèques de validation de données pour TypeScript. Voici quelques exemples qui utilisent un concept similaire à Zod :
La liste de ces validateurs n'est pas exhaustive. Nous avons porté notre attention sur Zod car il est simple à utiliser, et jouit d'une bonne notoriété dans la communauté TypeScript.
On le retrouve régulièrement dans des projets open-source et est supporté par beaucoup de librairies de l'écosystème TypeScript.
Pour finir
Désormais, vous avez tous les outils en main pour ne plus faire confiance à vos utilisateurs et valider leurs données avec les validateurs. En utilisant un système de validation, vous pouvez garantir que les données que vous manipulez sont correctes, et ce, à tout niveau, que ce soit dans le navigateur ou le serveur.
N'hésitez pas utiliser Zod pour valider vos données, et n'oubliez pas, ne faites jamais confiance à la donnée ! 🚀
Ressources
- Zod - La documentation officielle de Zod 📖
- Zod Playground - Un outil pour tester Zod en ligne 🕹️
- Le Général Zod - Un Kryptonien 🦸♂️