Проверяйте переменные окружения 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.
Отсутствие необходимой конфиденциальной информации теперь препятствует развертыванию в течение нескольких секунд при запуске с четким сообщением, вместо того чтобы проблема проявилась в виде недовольного пользователя спустя час.