Конфигурация
Приложения часто работают в разных окружениях. В зависимости от окружения следует использовать различные параметры конфигурации. Например, обычно локальное окружение полагается на определенные учетные данные базы данных, действительные только для локального экземпляра БД. В продакшн среде будет использоваться отдельный набор учетных данных БД. Поскольку переменные конфигурации изменяются, рекомендуется хранить переменные конфигурации в окружении.
Внешне определенные переменные среды видны внутри Node.js через process.env. Мы могли бы попытаться решить проблему множественных окружений, установив переменные среды отдельно в каждом окружении. Это может быстро стать громоздким, особенно в средах разработки и тестирования, где эти значения должны быть легко мока-тестируемы и/или изменены.
В Node.js-приложения, часто используются .env- файлы, содержащие пары ключ-значение, где каждый ключ представляет определенное значение, чтобы представлять каждое окружение. Запуск приложения в разных окружениях - это тогда просто вопрос замены в корректном .env файле.
Хорошим подходом для использования этого метода в Nest является создание ConfigModule, который предоставляет ConfigService, который загружает соответствующий файл .env файл. Хотя вы можете написать такой модуль самостоятельно, для удобства Nest предоставляет готовый пакет @nestjs/config. Мы рассмотрим этот пакет в текущей главе.
Установка
Чтобы начать использовать его, мы сначала устанавливаем необходимую зависимость.
$ npm i --save @nestjs/configПакет @nestjs/config внутри использует dotenv.
Начнем
После завершения процесса установки мы можем импортировать ConfigModule. Как правило, мы импортируем его в корневой AppModule и контролируем его поведение с помощью .forRoot(). На этом этапе пары ключ-значение переменной окружения парсятся и резолвятся. Позже мы увидим несколько вариантов доступа к классу ConfigService модуляConfigModule в других наших фича-модулях.
Приведенный выше код загрузит и распарсит .env файл из расположения по умолчанию (корневой каталог проекта), объединит пары ключ/значение из .env переменные среды, предназначенные для process.env, и сохранит результат в приватной структуре, к которой вы можете получить доступ через ConfigService. Метод forRoot() регистрирует провайдер ConfigService, который предоставляет метод get() для чтения этих parsed/merged переменных конфигурации. Поскольку @nestjs/config полагается на dotenv, он использует правила этого пакета для разрешения конфликтов в именах переменных среды. Когда ключ существует как в среде выполнения в качестве переменной окружения (например, через OS shell экспорт, например export DATABASE_USER=test), так и в .env-файле, переменная окружения выполнения имеет приоритет.
Пример .env файла выглядит примерно так:
DATABASE_USER=test
DATABASE_PASSWORD=testКастомное расположение env файла
По умолчанию пакет ищет .env-файл в корневом каталоге приложения. Чтобы указать другой путь для этого .env, установите свойство envFilePath (необязательного) объекта options, который вы передаете в forRoot(), следующим образом:
Вы также можете указать несколько путей для .env файлов, например:
Если переменная находится в нескольких файлах, то первая из них имеет приоритет.
Отключение загрузки env
Если вы не хотите его загружать .env file, но вместо этого хотел бы просто получить доступ к переменным среды из среды выполнения (как и в случае OS shell exports, например export DATABASE_USER=test), установите свойство объекта options ignoreEnvFile в true, как показано ниже:
Использование модуля глобально
Если вы хотите использовать ConfigModule в других модулях, вам нужно будет импортировать его (как это обычно делается с любым модулем Nest). Кроме того, объявите его глобальным модулем, установив для свойства isGlobal объекта options значение true, как показано ниже. В этом случае вам не нужно будет импортировать ConfigModule в другие модули, как только он будет загружен в корневой модуль (например, AppModule).
Кастомные файлы конфигурации
Для более сложных проектов можно использовать пользовательские файлы конфигурации для возврата вложенных объектов конфигурации. Это позволяет группировать связанные параметры конфигурации по функциям (например, параметры, связанные с базой данных) и хранить связанные параметры в отдельных файлах, чтобы помочь управлять ими независимо.
Пользовательский файл конфигурации экспортирует функцию фабрику, которая возвращает объект конфигурации. Объектом конфигурации может быть любой произвольно вложенный простой объект JavaScript. process.env будет содержать полностью резолвные пары ключ/значение переменных окружения (с .env-файлом и внешне определенные переменные резолвятся и объединяются, как описано выше). Поскольку вы управляете возвращаемым объектом конфигурации, вы можете добавить любую необходимую логику для приведения значений к соответствующему типу, установить значения по умолчанию и т.д. Например:
Мы загружаем этот файл, используя свойство load объекта options, который мы передаем в ConfigModule.forRoot() :
Значение, присвоенное свойству load, представляет собой массив, позволяющий загружать несколько конфигурационных файлов (например, load: [databaseConfig, authConfig])
Использование ConfigService
ConfigServiceЧтобы получить доступ к значениям конфигурации из нашего ConfigService, нам сначала нужно заинъектить ConfigService. Как и в случае с любым провайдером, нам нужно импортировать его содержащий модуль-ConfigModule-в модуль, который будет его использовать (если только вы не зададите свойство isGlobal в объекте options, переданном в ConfigModule.forRoot() значение true). Импортируйте его в модуль функций, как показано ниже.
Затем мы можем ввести его с помощью стандартной инъекции конструктора:
И далее используем его в нашем классе:
Как показано выше, используйте configService.get() , чтобы получить простую переменную окружения, передав ему имя переменной. Вы можете сделать намек на тип TypeScript, передав тип, как показано выше (например, get<string>(...)). Метод get() также может проходить через вложенный объект пользовательской конфигурации (созданный с помощью файла пользовательской конфигурации, как показано во втором примере выше. Метод get() также принимает необязательный второй аргумент, определяющий значение по умолчанию, которое будет возвращено, когда ключ не существует, как показано ниже:
Пространства имен конфигурации
ConfigModule позволяет определить и загрузить несколько пользовательских конфигурационных файлов, как показано в разделе пользовательские конфигурационные файлы выше. Вы можете управлять сложными иерархиями объектов конфигурации с помощью вложенных объектов конфигурации, как показано в этом разделе. Кроме того, вы можете вернуть "namespaced" объект конфигурации с помощью функции registerAs() следующим образом:
Как и в случае с пользовательскими конфигурационными файлами, внутри вашей фабричной функции registerAs() process.env будет содержать полностью зарезолвленные пары ключ/значение переменной окружения (с .env-файл и внешне определенные переменные зарезолвленны и объединены, как описано выше).
Функция registerAs экспортируется из пакета @nestjs/config.
Загрузите namespaced конфигурацию с помощью свойства load объекта options метода forRoot() точно так же, как вы загружаете пользовательский файл конфигурации:
Теперь, чтобы получить значение host из пространства имен database, используйте точечную нотацию. Используйте 'database' в качестве префикса к имени свойства, соответствующего имени пространства имен (передается в качестве первого аргумента функции registerAs() ):
Разумной альтернативой является прямая инъекция пространства имен database. Это позволяет нам извлечь выгоду из строгой типизации:
ConfigType экспортируется из пакета @nestjs/config.
Частичная регистрация
До сих пор мы обрабатывали конфигурационные файлы в нашем корневом модуле (например, AppModule) с помощью метода forRoot(). Возможно, у вас есть более комплексная структура проекта, с фича-специфичными конфигурационными файлами, расположенными в нескольких разных каталогах. Вместо того чтобы загружать все эти файлы в корневой модуль, пакет @nestjs/config предоставляет функцию частичной регистрации, которая ссылается только на файлы конфигурации, связанные с каждым модулем функций. Используйте статический метод forFeature() в фича-модуле для выполнения этой частичной регистрации, как показано ниже:
В некоторых случаях вам может потребоваться получить доступ к свойствам, загруженным через частичную регистрацию с помощью хука onModuleInit(), а не в конструкторе. Это происходит потому, что метод forFeature() запускается во время инициализации модуля, и порядок инициализации модуля не определен. Если вы обращаетесь к значениям, загруженным таким образом другим модулем в конструкторе, то модуль, от которого зависит конфигурация, возможно, еще не инициализирован. Метод onModuleInit() запускается только после инициализации всех модулей, от которых он зависит, поэтому этот метод безопасен.
Валидация схем
Это стандартная практика, чтобы создать исключение во время запуска приложения, если необходимые переменные среды не были предоставлены или если они не соответствуют определенным правилам проверки. Пакет @nestjs/config позволяет использовать пакет Joi для поддержки этого типа проверки. С помощью Joi вы определяете схему объекта и проверяете ее соответствие объектам JavaScript.
Установите Joi (и его типы, для пользователей TypeScript):
Последняя версия @hapi/joi требует, чтобы вы работали под управлением Node v12 или более поздней версии. Для более старых версий node, пожалуйста, установите v16.1.8. Это происходит в основном после выпуска версии v17.0.2, которая вызывает ошибки во время сборки. Для получения дополнительной информации, пожалуйста, обратитесь к их документации и этому github issue.
Теперь мы можем определить схему проверки Joi и передать ее через свойство validationSchema объекта options метода forRoot(), как показано ниже:
По умолчанию все ключи схемы считаются необязательными. Здесь мы устанавливаем значения по умолчанию для NODE_ENV и PORT, которые будут использоваться, если мы не предоставим эти переменные в среде (.env среды или процесса). Кроме того, мы можем использовать метод проверки required(), чтобы потребовать, чтобы значение было определено в среде (.env среды или процесса). В этом случае шаг проверки вызовет исключение, если мы не предоставим переменную в среде. Дополнительные сведения о построении схем проверки см. в разделе методы проверки Joi.
По умолчанию неизвестные переменные среды (переменные среды, ключи которых отсутствуют в схеме) разрешены и не вызывают исключения проверки. По умолчанию регистрируются все ошибки проверки. Вы можете изменить это поведение, передав объект options через ключ validationOptions объекта options forRoot(). Этот объект options может содержать любое из стандартных свойств параметров проверки, предоставляемых параметрами проверки Joi. Например, чтобы изменить две вышеперечисленные настройки, передайте следующие параметры:
Пакет @nestjs/config использует настройки по умолчанию:
allowUnknown: определяет, следует ли разрешать неизвестные ключи в переменных окружения. Значение по умолчанию-trueabortEarly: еслиtrue, останавливает проверку при первой ошибке; еслиfalse, возвращает все ошибки. По умолчанию используется значениеfalse.
Обратите внимание, что после того, как вы решите передать объект validationOptions, все параметры, которые вы явно не передадите, будут по умолчанию иметь стандартные значения Joi (а не значения по умолчанию из@nestjs/config). Например, если вы оставите allowUnknowns неопределенным в своем пользовательском объекте validationOptions, он будет иметь значение по умолчанию false. Поэтому, вероятно, безопаснее всего указать оба этих параметра в вашем пользовательском объекте.
Кастомные геттер функции
ConfigService определяет дженерик метод get() для получения значения конфигурации по ключу. Мы также можем добавить getter функции, чтобы обеспечить немного более естественный код-стайл:
Теперь мы можем использовать функцию геттера следующим образом:
app.service.ts
Расширяемые переменные
Пакет @nestjs/config поддерживает расширение переменных окружения. С помощью этого метода можно создавать вложенные переменные среды, в которых одна переменная упоминается в определении другой. Например:
С помощью этой конструкции переменная SUPPORT_EMAIL преобразуется в 'support@mywebsite.com' . Обратите внимание на использование ${...} синтаксис для запуска разрешения значения переменной APP_URL внутри определения SUPPORT_EMAIL.
Для этой функции, пакет @nestjs/config внутренне использует dotenv-expand.
Включите расширение переменной окружения с помощью свойства expandVariables в объекте options, переданном методу forRoot() ConfigModule, как показано ниже:
Использование в main.ts
Хотя наша конфигурация хранится в сервисе, она все еще может быть использована в main.ts. Таким образом, вы можете использовать его для хранения переменных, таких как порт приложения или хост CORS.
Чтобы получить доступ к нему, вы должны использовать app.get(), за которым следует ссылка на сервис:
Затем вы можете использовать его как обычно, вызвав метод get с ключом конфигурации:
Last updated