Перевіряйте змінні середовища Node.js за допомогою Zod та TypeScript.
Припиніть читати значення з process.env у всьому коді Node.js. Один файл env.ts, перевірений за допомогою Zod, виявляє відсутні секрети під час запуску та забезпечує додатку конфігурацію у форматі TypeScript із типами.
Уявіть собі розгортання у п’ятницю після обіду. Компіляція пройшла успішно, сервер запустився, і всі пішли додому. Через годину користувачі повідомляють, що входи не вдаються. Виявляється, ніхто не встановив значення JWT_SECRET у продакшн-середовищі. Додаток почав працювати без проблем, але зламався лише тоді, коли перше запитання потрапило на код, який потребував відсутнього значення.
Часте використання process.env у всьому кодовому базі підвищує ймовірність таких інцидентів. Далі показано, як замінити цю практику на валідований, типізований модуль конфігурації з використанням Zod та TypeScript.
Звичайний підхід
Більшість кодів на Node.js отримують конфігурацію безпосередньо там, де вона потрібна: порт у одному файлі, адреса бази даних — у іншому.
// Some random controller file
const port = process.env.PORT || 3000;
mongoose.connect(process.env.MONGO_URI);
Це зручно, але має три серйозні проблеми.
- Відсутня безпека типів. У TypeScript
process.env.PORTмає типstring | undefined. Якщо потрібне число, кожен місце виклику мусить його розпарсити вручну. - Тихі збої. Якщо
MONGO_URIвідсутній, процес не завершується під час запуску. Він зупиняється лише тоді, коли нарешті виконується ця конкретна строка, можливо, через кілька годин після запуску, який здавався успішним. - Відсутнє єдине джерело інформації. Початківець не має списку змінних, необхідних додатку. Їхня єдина можливість — шукати
process.envу всьому репозиторії.
Єдиний файл-контролер
Рішенням є припинити змінювати process.env у бізнес-логіці. Один модуль, назвімо його env.ts, читає дані середовища один раз під час запуску, перевіряє їх та експортує об’єкт із суворою типізацією. Усі інші компоненти імпортують цей об’єкт.
Задачу перевірки виконує Zod — бібліотека для верифікації схем, орієнтована на TypeScript.
Встановіть її
npm install zod
Напишіть схему
Розмістіть модуль у src/config/env.ts та детально описайте, яким має бути середовище.
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;
Що робить цей модуль
- Він визначає необхідні умови.
MONGO_URI— це обов’язкова рядкова змінна.PORTтакож надсилається у вигляді рядка, і функція.transform(Number)перетворює його, при цьому значення за замовчуванням становить 3000.NODE_ENVмає бути одним із трьох дозволених значень. - Він швидко фіксує помилки. Функція
safeParseвиконується в момент імпорту файлу, тому його потрібно розмістити на самому початку файлу-вхідного точки, чи тоapp.ts, чиserver.ts. Якщо бракує якоїсь обов’язкової змінної або вона має неправильну форму, результат відображає повідомлення про помилку, у якому точно вказується, що пішло не так, аprocess.exit(1)зупиняє процес до того, як він почне обробку запитів. - Він експортує об’єкт із типами. У разі успіху оброблені дані містять типи, визначені Zod, тож
env.PORTвже є числом.
З того моменту будь-який файл може імпортувати env та використовувати його.
Що ви отримуєте
- Автодоповнення. При введенні
env.у вашому редакторі відображається список усіх доступних змінних. - Без розкиданих альтернатив. Схеми типу
|| "default_value"зникають із контролерів, оскільки значення за замовчуванням знаходяться у схемі. - Вбудована документація. Схема є точним списком того, що потрібно для роботи додатку, і водночас відповідає на запитання новачків щодо того, що має бути у файлі
.env.
Відсутність потрібної таємної змінної тепер зупиняє розгортання протягом кількох секунд під час запуску з чітким повідомленням, замість того щоб проблема проявилась у розлюченому користувачеві через годину.