Typsäker miljökonfiguration och validering vid körning
Validera miljövariabler och extern indata vid körning med schemabibliotek som härleder statiska typer.
Typsäker miljökonfiguration och validering vid körning är en gratis lektion i Bootcamp i backendutveckling med Node.js på CoddyKit. Detta är lektion 3 av 4. Ni kan läsa hela lektionen gratis nedan och sedan öva praktiskt i webbläsaren med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt. Den ingår i lärvägen för Bootcamp i backendutveckling med Node.js, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i Bootcamp i backendutveckling med Node.js innehåller totalt 4 lektioner.
Varför validera process.env?
I Node.js är varje värde i process.env en sträng eller undefined — körmiljön ger inga garantier.
process.env.PORTkan vara"3000",""eller saknas helt.- Ett stavfel som
DATABSE_URLger tyst värdetundefined. - TypeScript typifierar
process.envsomRecord<string, string | undefined>, så det kan inte upptäcka saknade nycklar.
Om konfiguration läses in lite här och där i appen upptäcks krascher djupt inne i requesthanterare — långt efter att programmet har startat. Lösningen är att validera en gång vid uppstart och avbryta direkt med ett tydligt meddelande.
// Untyped, unsafe access scattered everywhere
const port = process.env.PORT; // string | undefined
const dbUrl = process.env.DATABASE_URL; // string | undefined
console.log(typeof port); // "string" or "undefined"
console.log(Number(process.env.MISSING)); // NaN — silent failureSchemabibliotek och typhärledning
Ett schemabibliotek låter dig beskriva datastruktur och begränsningar en gång och sedan både validera vid körning OCH härleda en statisk TypeScript-typ från samma definition.
- Populära alternativ är Zod, Valibot, ArkType och TypeBox.
- En enda källa till sanning — schemat — skapar både kontrollen vid körning och typen vid kompilering.
- Ingen duplicerad
interfacesom kan hamna ur synk.
Vi använder Zod, som är vanligast i Node.js-ekosystemet. z.infer<typeof schema> hämtar den typ som schemat validerar.
import { z } from "zod";
const UserSchema = z.object({
id: z.number().int(),
email: z.string().email(),
});
// Static type inferred from the runtime schema
type User = z.infer<typeof UserSchema>;
// type User = { id: number; email: string }Ett första miljövariabelschema
Vi beskriver den miljö som tjänsten behöver. Eftersom värdena i process.env alltid är strängar måste schemat konvertera numeriska fält och begränsa strängfält.
z.coerce.number()omvandlar"3000"till3000.z.enum([...])begränsar ett värde till en fast uppsättning.- Genom att kedja anrop som
.min()och.url()lägger du till begränsningar vid körning.
Definiera schemat i en egen modul (till exempel src/env.ts) så att det importeras en gång vid uppstart.
import { z } from "zod";
export const EnvSchema = z.object({
NODE_ENV: z.enum(["development", "test", "production"]),
PORT: z.coerce.number().int().positive().default(3000),
DATABASE_URL: z.string().url(),
JWT_SECRET: z.string().min(32),
});Parsa vid uppstart
Anropa schema.parse(process.env) en gång, högst upp i startfilen. Om valideringen misslyckas kastar Zod ett ZodError och processen avslutas innan den tar emot någon trafik.
parse()returnerar ett fullständigt typat och validerat objekt.- Konverterade och standardiserade värden har redan tillämpats.
- Exportera resultatet så att resten av appen importerar ett typat
env-objekt i stället för att komma åtprocess.envdirekt.
import { z } from "zod";
import { EnvSchema } from "./env-schema";
export const env = EnvSchema.parse(process.env);
// env.PORT is number, env.NODE_ENV is a narrowed union
const server = createServer();
server.listen(env.PORT, () => {
console.log(`Listening on ${env.PORT} in ${env.NODE_ENV}`);
});safeParse för tydliga felmeddelanden
En rå stack trace från ZodError är svåröverskådlig. Använd safeParse för att få ett resultatobjekt som du kan formatera till ett lättläst uppstartsmeddelande och sedan avsluta processen avsiktligt.
safeParsereturnerar{ success: true, data }eller{ success: false, error }— det kastar aldrig ett undantag.error.flatten().fieldErrorsgrupperar meddelanden per fält.- Avsluta med
process.exit(1)så att orkestrerare (Docker, PM2, k8s) ser att uppstarten misslyckades.
import { z } from "zod";
const EnvSchema = z.object({
PORT: z.coerce.number().int().positive(),
DATABASE_URL: z.string().url(),
});
const parsed = EnvSchema.safeParse(process.env);
if (!parsed.success) {
console.error("Invalid environment variables:");
console.error(parsed.error.flatten().fieldErrors);
process.exit(1);
}
export const env = parsed.data;Ett fristående körbart exempel
Här är en fristående demonstration av mönstret validera-och-härled med ett vanligt objekt i stället för process.env, så att en onlinebedömare kan köra det utan konfiguration.
Det visar konvertering, ett standardvärde, en enum och en väg för lättlästa fel — samma tekniker som du skulle använda vid riktig inläsning av miljövariabler.
import { z } from "zod";
const Schema = z.object({
NODE_ENV: z.enum(["development", "production"]).default("development"),
PORT: z.coerce.number().int().positive(),
});
function loadConfig(raw) {
const result = Schema.safeParse(raw);
if (!result.success) {
throw new Error(JSON.stringify(result.error.flatten().fieldErrors));
}
return result.data;
}
const config = loadConfig({ PORT: "8080" });
console.log(config); // { NODE_ENV: 'development', PORT: 8080 }
console.log(typeof config.PORT); // numberLäsa in .env-filer med ESM
Lokalt lagrar du konfiguration i en .env-fil. Biblioteket dotenv läser in den i process.env. Med ESM och TypeScript ska du läsa in den innan någon modul som läser konfiguration importeras.
- Moderna Node (v20.6+) har flaggan
--env-file=.envinbyggd — ingen beroendepaketering behövs. - Om du använder
dotenvska du läsa indotenv/configallra först, eftersom ESM-importer hissas och utvärderas först. - Checka aldrig in riktiga hemligheter; checka in en
.env.examplesom dokumenterar obligatoriska nycklar.
// Option A: built-in (Node 20.6+), no import needed
// $ node --env-file=.env dist/index.js
// Option B: dotenv — must run first
import "dotenv/config";
import { EnvSchema } from "./env-schema";
export const env = EnvSchema.parse(process.env);Återanvända schemat för indata i requests
Exakt samma metod validerar opålitliga indata vid körning — request bodies, query-parametrar och webhook-payloads. Nätverksdata är lika otypad som process.env.
- Definiera ett schema per endpoint och kör sedan
parsepå inkommande JSON. - Vid fel svarar du med
400i stället för att krascha. - Det parsade resultatet är fullständigt typat för resten av handlern.
import { z } from "zod";
const CreateUserBody = z.object({
email: z.string().email(),
age: z.coerce.number().int().min(0).optional(),
});
function handleCreateUser(rawBody, res) {
const result = CreateUserBody.safeParse(rawBody);
if (!result.success) {
res.status(400).json({ errors: result.error.flatten() });
return;
}
const body = result.data; // { email: string; age?: number }
// ...persist body
}Transformationer och härledd konfiguration
Scheman kan transformera värden under parsningen och skapa konfiguration som är redo att användas. Då hålls konverteringslogiken nära valideringsregeln.
.transform()mappar ett validerat värde till en ny struktur.- Miljövariabler med kommaseparerade strängar blir arrayer och flaggor blir booleska värden.
- Den härledda typen återspeglar det transformerade resultatet, inte råindatan.
import { z } from "zod";
const EnvSchema = z.object({
// "a.com,b.com" -> ["a.com", "b.com"]
CORS_ORIGINS: z.string()
.transform((s) => s.split(",").map((o) => o.trim()))
.pipe(z.array(z.string().url())),
// "true"/"false" string -> boolean
ENABLE_CACHE: z
.enum(["true", "false"])
.transform((v) => v === "true")
.default("false"),
});Regler mellan fält med refine
Ibland beror giltigheten på relationer mellan fält — till exempel måste en hemlighet anges i produktion, medan ett standardvärde räcker lokalt. Använd .refine() eller .superRefine() på objektschemat.
- Kontrollen körs efter att de enskilda fälten har parsats.
- Du anger ett anpassat meddelande och en
pathså att felet pekar på rätt fält. - Detta kodifierar affärsregler som ett platt schema per fält inte kan uttrycka.
import { z } from "zod";
const EnvSchema = z
.object({
NODE_ENV: z.enum(["development", "production"]),
SENTRY_DSN: z.string().url().optional(),
})
.refine(
(e) => e.NODE_ENV !== "production" || !!e.SENTRY_DSN,
{ message: "SENTRY_DSN is required in production", path: ["SENTRY_DSN"] }
);Exportera en typad konfigurationssingleton
Målet är att resten av kodbasen aldrig ska komma åt process.env. Den importerar i stället ett enda validerat och typat env-objekt.
- Centraliserad åtkomst gör att TypeScript kan komplettera varje nyckel och upptäcka stavfel vid kompilering.
- Om du byter namn på en variabel behöver du bara ändra i en fil.
- Tester kan importera ett schema och skicka in mockobjekt i stället för att ändra globalt tillstånd.
// src/config.ts
import "dotenv/config";
import { z } from "zod";
const EnvSchema = z.object({
NODE_ENV: z.enum(["development", "test", "production"]).default("development"),
PORT: z.coerce.number().int().positive().default(3000),
DATABASE_URL: z.string().url(),
});
const parsed = EnvSchema.safeParse(process.env);
if (!parsed.success) {
console.error("❌ Invalid env:", parsed.error.flatten().fieldErrors);
process.exit(1);
}
export const env = Object.freeze(parsed.data);
// elsewhere: import { env } from "./config";Snabbkontroll
Testa din förståelse av det typsäkra konfigurationsmönstret.
Sammanfattning
Du har lärt dig att göra konfiguration och externa indata typsäkra i moderna Node.js:
- Varför:
process.envoch nätverksdata består av otypade strängar; validera en gång och avbryt direkt vid fel. - Scheman: ett bibliotek som Zod ger validering vid körning samt härledda statiska typer från en enda definition (
z.infer). - Inläsning av miljövariabler: konvertera tal, begränsa värden med enum och standardvärden, och läs in
.envvia--env-fileellerdotenv/configinnan värdena läses. - safeParse: formatera
error.flatten().fieldErrorsoch körprocess.exit(1)vid fel. - Utöver miljövariabler: återanvänd scheman för request bodies, lägg till
.transform()för härledd konfiguration och.refine()för regler mellan fält. - Resultat: exportera en fryst, typad
env-singleton som hela appen importerar.
Lär dig JavaScript med en AI-lärare – gratis
Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.
- Kurser
- 22
- Lektioner
- 92
Vanliga frågor
Är lektionen ”Typsäker miljökonfiguration och validering vid körning” gratis?
Ja – hela texten till ”Typsäker miljökonfiguration och validering vid körning” kan läsas gratis här på webben. Om Ni vill öva interaktivt med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt och låsa upp resten av kursen i Bootcamp i backendutveckling med Node.js, kan Ni uppgradera till CoddyKit PRO. Kursen i Bootcamp i backendutveckling med Node.js innehåller totalt 4 lektioner.
Vad lär jag mig i ”Typsäker miljökonfiguration och validering vid körning”?
Validera miljövariabler och extern indata vid körning med schemabibliotek som härleder statiska typer. Ni övar på Bootcamp i backendutveckling med Node.js med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.
Behöver jag någon erfarenhet för att börja lära mig Bootcamp i backendutveckling med Node.js?
Du behöver inga förkunskaper. Utbildningen i Bootcamp i backendutveckling med Node.js på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 3 av 4.
Hur lång tid tar lektionen ”Typsäker miljökonfiguration och validering vid körning”?
De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.
Kan jag skriva och köra kod i den här Bootcamp i backendutveckling med Node.js-lektionen?
Ja. Varje Bootcamp i backendutveckling med Node.js-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.
Alla lektioner i den här kursen
- Migrera från CommonJS till inbyggda ES-moduler
- Konfigurera tsconfig för Node-backendprojekt
- Typsäker miljökonfiguration och validering vid körning
- Snabba iterationer med tsx, hot reload och källkartor