Einführung in Zod Contract - Typsicherheit für API-Verträge
Hattest du schon mal, dass deine API explodiert ist, weil jemand einen String geschickt hat, wo du eine Zahl erwartet hast? Ja, ich auch. Deshalb habe ich angefangen, Zod für API-Verträge zu verwenden, und ehrlich gesagt, es war ein Game Changer.
Was ist Zod?
Zod ist eine TypeScript-Validierungsbibliothek, die etwas ziemlich Cooles macht - du definierst deine Datenstruktur einmal, und boom, du bekommst sowohl Laufzeitvalidierung ALS AUCH TypeScript-Typen. Keine manuelle Synchronisierung von Typen und Validierung mehr. Es ist speziell für TypeScript gebaut, was bedeutet, es funktioniert einfach… einfach.
import { z } from 'zod'
const UserSchema = z.object({
id: z.string().uuid(),
name: z.string().min(1).max(100),
email: z.string().email(),
age: z.number().int().positive().optional()
})
type User = z.infer<typeof UserSchema>
Siehst du die letzte Zeile? Das ist alles, was du brauchst, um einen TypeScript-Typ aus deinem Schema zu bekommen. Keine Duplizierung, kein Drift. Einmal definieren, überall verwenden.
Warum ich zu Zod gewechselt bin
Typinferenz ist Magie: Schreibe dein Schema einmal, bekomme TypeScript-Typen kostenlos. Früher musste ich separate Typdefinitionen und Validierungslogik pflegen. Sie drifteten auseinander, Bugs schlichen sich ein. Nicht mehr.
Komponierbarkeit: Du kannst komplexe Schemas aus einfachen bauen. Musst du eine Adresse zu deinem User hinzufügen? Einfach erweitern:
const AddressSchema = z.object({
street: z.string(),
city: z.string(),
zipCode: z.string().regex(/^\d{5}$/)
})
const UserWithAddressSchema = UserSchema.extend({
address: AddressSchema
})
Fehlermeldungen, die tatsächlich helfen: Wenn die Validierung fehlschlägt, sagt dir Zod genau, was schief gelaufen ist und wo. Keine kryptischen Fehlermeldungen mehr.
const result = UserSchema.safeParse({
id: 'invalid-uuid',
name: '',
email: 'not-an-email'
})
if (!result.success) {
console.log(result.error.issues)
// Detaillierte Fehlerinformationen für jeden Validierungsfehler
}
Vergleich mit Alternativen
Joi: Eine ausgereifte Validierungsbibliothek, der jedoch das TypeScript-First-Design fehlt. Sie benötigen zusätzliche Tools wie joi-to-typescript, um Typen zu generieren, was zu potenziellen Inkonsistenzen führt.
Yup: Ähnlich wie Joi mit besserer TypeScript-Unterstützung, aber die Typinferenz ist nicht so nahtlos wie bei Zod. Schemadefinitionen können ausführlicher sein.
io-ts: Bietet hervorragende Typsicherheit, hat aber eine steilere Lernkurve und eine komplexere API. Zod bietet ähnliche Garantien mit besserer Ergonomie.
Class-validator: Funktioniert gut mit klassenbasierten Ansätzen, erfordert jedoch Dekoratoren und bietet nicht das gleiche Maß an Komponierbarkeit wie Zod.
Zod findet die richtige Balance zwischen Typsicherheit, Entwicklererfahrung und Laufzeitvalidierungsleistung.
Contract-First vs. Code-First-Ansatz
Contract-First: Definieren Sie zuerst Ihre API-Verträge (Schemas) und implementieren Sie dann die Logik. Dieser Ansatz stellt sicher, dass sich Client und Server auf die Datenstruktur einigen, bevor Code geschrieben wird.
// Definieren Sie den Vertrag
const CreateUserRequest = z.object({
name: z.string().min(1),
email: z.string().email()
})
const CreateUserResponse = z.object({
id: z.string().uuid(),
name: z.string(),
email: z.string(),
createdAt: z.string().datetime()
})
// Die Implementierung folgt dem Vertrag
type CreateUserInput = z.infer<typeof CreateUserRequest>
type CreateUserOutput = z.infer<typeof CreateUserResponse>
Code-First: Schreiben Sie zuerst Ihre Implementierung und fügen Sie dann bei Bedarf Validierung hinzu. Dies kann zu Inkonsistenzen führen und erschwert es, Verträge mit Clients zu teilen.
Mit Zod wird der Contract-First-Ansatz natürlich. Ihre Schemas dienen sowohl als Dokumentation als auch als Validierung und stellen sicher, dass sich Ihre API genau wie angegeben verhält.
Wann sollte man Contract-First mit Zod verwenden?
Die Contract-First-Entwicklung mit Zod ist ideal, wenn:
- Sie APIs erstellen, die von mehreren Clients genutzt werden
- Sie Typdefinitionen zwischen Frontend und Backend teilen müssen
- API-Zuverlässigkeit und Datenkonsistenz kritisch sind
- Sie Validierungsfehler früh in der Entwicklung abfangen möchten
- Sie in einem Team arbeiten, in dem klare Verträge die Zusammenarbeit verbessern
Erste Schritte
Die Installation von Zod ist unkompliziert:
npm install zod
Beginnen Sie klein, indem Sie Schemas für Ihre kritischsten Endpunkte definieren. Wenn Sie die Vorteile sehen, erweitern Sie die Abdeckung auf Ihre gesamte API-Oberfläche.
import { z } from 'zod'
import express from 'express'
const app = express()
const LoginSchema = z.object({
email: z.string().email(),
password: z.string().min(8)
})
app.post('/login', (req, res) => {
const result = LoginSchema.safeParse(req.body)
if (!result.success) {
return res.status(400).json({ errors: result.error.issues })
}
// result.data ist jetzt typisiert und validiert
const { email, password } = result.data
// ... Authentifizierungslogik
})
Fazit
Zod macht Typsicherheit und Laufzeitvalidierung nahtlos zusammenarbeiten. Keine manuelle Synchronisierung von Typen und Validierung mehr. Keine Überraschungen zur Laufzeit.
Fang mit einem Endpoint an. Schau, wie es sich anfühlt. Ich wette, du wirst es überall verwenden wie ich.
Nächster Post: Wir bauen eine echte API mit Zod - Validierungs-Middleware, Fehlerbehandlung, das ganze Zeug.
Keep pushing forward and savor every step of your coding journey.
