Validation des réponses API en temps réel : Pourquoi TypeScript ne suffit pas
TypeScript vérifie les types uniquement à la compilation. Les données des API arrivent à l'exécution sans garantie qu'elles correspondent à vos interfaces. Sans validation supplémentaire, les incohérences se manifestent par des erreurs visibles pour l'utilisateur : champs indéfinis, types erronés, objets manquants.
Problèmes sans contrôles en temps réel
Les interfaces TypeScript donnent un faux sentiment de sécurité. Voici un code typique sans validation :
interface User {
id: number;
name: string;
email: string;
}
const getUser = async (): Promise<User> => {
const res = await fetch('/api/user');
return res.json(); // Pas de vérification des données réelles
};
TypeScript fait confiance à l'annotation de type et ignore la réponse réelle du serveur. Risques principaux :
- Changements de structure backend :
full_name→fullNameentraîneundefined. - Incohérences de types : chaîne
"123"au lieu du nombre123provoque une concaténation au lieu d'une addition. - Champs conditionnels :
addressabsent dans les cas limites, crash suruser.address.city. - API tierces avec docs obsolètes.
Bibliothèques de validation de schémas
La solution ? Les bibliothèques de validation de schémas en temps réel. Elles analysent les données réelles et lèvent des erreurs en cas d'incohérence. Meilleures options TypeScript :
- Zod : Infère les types à partir des schémas, écosystème immense.
- Yup : Parfait avec Formik.
- Valibot : Léger, compatible tree-shaking.
- Joi : Origines Node.js, orienté backend.
- ArkType : Priorité à la performance.
Mise en œuvre avec Zod
Zod réunit schéma, types et validation en un seul outil. Exemple utilisateur :
import { z } from 'zod';
const UserSchema = z.object({
id: z.number(),
name: z.string(),
email: z.string().email(),
});
type User = z.infer<typeof UserSchema>;
const getUser = async (): Promise<User> => {
const res = await fetch('/api/user');
const data = await res.json();
return UserSchema.parse(data); // Erreur en cas d'incohérence
};
parse() lève une ZodError détaillée en cas d'échec. Utilisez safeParse() pour un objet avec success et error.
Mise à l'échelle dans de vrais projets
Pour les grandes applications, centralisez les schémas pour tous les endpoints. Encapsulez fetch comme ceci :
const apiFetch = async <T>(url: string, schema: z.ZodSchema<T>): Promise<T> => {
const res = await fetch(url);
const data = await res.json();
return schema.parse(data);
};
const users = await apiFetch('/api/users', z.array(UserSchema));
Gestion des erreurs : Journalisez vers Sentry, affichez des messages conviviaux. Pour les tableaux, validez chaque élément.
- Utilisez
z.array(UserSchema)pour les listes. z.union()pour les réponses polymorphes.z.lazy()pour les structures récursives.z.transform()pour normaliser les données.
Points clés
- TypeScript ne garantit pas les types en temps réel pour les données externes : API, localStorage, params URL.
- La validation de schémas détecte les incohérences tôt, réduisant le temps de débogage.
- Zod est la référence frontend : types inférés des schémas, intégration facile.
- Dans les équipes avec backend séparé, elle évite les pannes silencieuses.
- Passez à l'échelle avec des wrappers fetch pour la cohérence.
La validation en temps réel comble l'écart entre les vérifications à la compilation de TypeScript et l'exécution. En production, elle réduit drastiquement les bugs dus à des contrats API désynchronisés.
— Editorial Team
Aucun commentaire pour le moment.