Validieren Sie Node.js-Umgebungsvariablen mit Zod und TypeScript.
Hören Sie auf, überall im Node.js-Code auf process.env zuzugreifen. Eine mit Zod validierte env.ts-Datei erkennt bei Start fehlende Geheimnisse und stellt der Anwendung eine typisierte TypeScript-Konfiguration zur Verfügung.
Stellen Sie sich einen Einsatz am Freitagnachmittag vor. Der Build ist erfolgreich, der Server startet und alle gehen nach Hause. Eine Stunde später melden Benutzer, dass die Anmeldungen fehlschlagen. Es stellt sich heraus, dass niemand in der Produktionsumgebung JWT_SECRET festgelegt hat. Die Anwendung startete problemlos und funktionierte erst dann nicht mehr, als die erste Anfrage auf den Code stieß, der den fehlenden Wert benötigte.
Das Überall-Auslesen von process.env in einer Codebasis erhöht das Risiko für solche Vorfälle. Im Folgenden wird gezeigt, wie man diese Gewohnheit durch ein validiertes, typisiertes Konfigurationsmodul unter Verwendung von Zod und TypeScript ersetzen kann.
Der übliche Ansatz
Die meisten Node.js-Programme holen die Konfiguration genau dort ab, wo sie benötigt wird: eine Port-Nummer in einer Datei, eine Datenbank-Adresse in einer anderen.
// Some random controller file
const port = process.env.PORT || 3000;
mongoose.connect(process.env.MONGO_URI);
Es ist praktisch, hat aber drei ernsthafte Probleme.
- Keine Typsicherheit. In TypeScript ist
process.env.PORTvon Typstring | undefined. Wenn man eine Zahl benötigt, muss jeder Aufrufort diesen Wert manuell parsen. - Stille Fehler. Wenn
MONGO_URIfehlt, stürzt der Prozess beim Starten nicht ab. Er stürzt erst ab, wenn diese bestimmte Zeile schließlich ausgeführt wird – möglicherweise Stunden nach einem scheinbar erfolgreichen Deployment. - Keine einzige Quelle der Wahrheit. Ein Neuling hat keine Liste der Variablen, die die Anwendung benötigt. Ihre einzige Option besteht darin, das gesamte Repository nach
process.envdurchzusuchen.
Ein einziger Kontrolldatei
Die Lösung besteht darin, in der Geschäftslogik den Zugriff auf process.env zu unterbinden. Ein einzelnes Modul, nennen wir es env.ts, liest die Umgebungsdaten beim Start einmal ein, prüft sie und gibt ein stark typisiertes Objekt aus. Alle anderen Module importieren dieses Objekt.
Zod, eine auf TypeScript ausgerichtete Bibliothek für Schema-Validierung, übernimmt die Validierung.
Installieren Sie es
npm install zod
Erstellen Sie das Schema
Platzieren Sie das Modul in src/config/env.ts und beschreiben Sie genau, wie die Umgebung aussehen muss.
import dotenv from 'dotenv';
import { z } from 'zod';
// Load variables from .env file (if in development)
dotenv.config();
// 1. Define the schema
const envSchema = z.object({
PORT: z.string().transform(Number).default('3000'),
NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),
MONGO_URI: z.string(),
JWT_SECRET: z.string(),
JWT_EXPIRES_IN: z.string().default('1d'),
});
// 2. Parse the environment against the schema
const _env = envSchema.safeParse(process.env);
// 3. Fail fast if it's invalid
if (!_env.success) {
console.error('Invalid environment variables:', _env.error.format());
process.exit(1); // Crash the app immediately!
}
// 4. Export the typed, validated object
export const env = _env.data;
Was das Modul tut
- Es deklariert Erwartungen.
MONGO_URIist eine erforderliche Zeichenkette.PORTwird als Zeichenkette übergeben und durch.transform(Number)in eine Zahl umgewandelt, wobei 3000 als Standardwert verwendet wird.NODE_ENVmuss einen der drei zulässigen Werte sein. - Es führt schnell zu einem Fehler.
safeParsewird sofort ausgeführt, sobald die Datei importiert wird, daher sollte sie ganz oben im Eingangspunkt, sei esapp.tsoderserver.ts, importiert werden. Wenn eine erforderliche Variable fehlt oder fehlerhaft ist, wird ein Fehler gemeldet, die Fehlerausgabe gibt genau an, was schiefgelaufen ist, undprocess.exit(1)stoppt den Prozess, bevor er Daten anfordern kann. - Es exportiert ein typisiertes Objekt. Bei Erfolg enthält die parsierte Daten die von Zod abgeleiteten Typen, sodass
env.PORTbereits eine Zahl ist.
Von da an kann jede Datei env importieren und verwenden.
Was Sie erhalten
- Autocomplete. Wenn Sie in Ihrem Editor
env.eingeben, werden alle verfügbaren Variablen aufgelistet. - Keine verstreuten Fallback-Lösungen. Die Muster
|| „default_value“verschwinden aus den Controllern, da die Standardwerte im Schema enthalten sind. - Integrierte Dokumentation. Das Schema ist eine genaue Liste dessen, was die Anwendung zum Laufen benötigt, und beantwortet außerdem die Frage neuer Nutzer darüber, was in
.envgehören sollte.
Ein fehlendes Geheimnis verhindert nun bereits bei der Initialisierung innerhalb von Sekunden einen Deployment-Versuch mit einer klaren Meldung, anstatt erst eine Stunde später als verärgerte Nutzer zu auftreten.