Hola a todos, hoy os voy a explicar como podemos cargar diferentes variables según en el entorno en el que nos encontremos.
Cuando tenemos una aplicación es normal que tengamos diferentes entornos de ejecución donde haya variables que cambien en cada entorno, el ejemplo más común es la conexión de base de datos. Lo más normal es desarrollo y producción.
En NestJS, nos provee una funcionalidad de configuración para cargar por variables de entorno según le indiquemos.
Sino sabes como crear un proyecto en NestJS, te dejo un pequeño tutorial donde lo explico:
Necesitamos instalar las siguientes dependencias:
dotenv es necesario para que podamos cargar variables de entorno.
En app.module, importamos el módulo de configuración y llamamos al método forRoot()
import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import { AppController } from './app.controller'; import { AppService } from './app.service'; @Module({ imports: [ ConfigModule.forRoot() ], controllers: [AppController], providers: [AppService], }) export class AppModule {}
Seguimos en app.module, añadimos al final de las importaciones la siguiente línea:
require('dotenv').config()
Quedando así:
import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import { AppController } from './app.controller'; import { AppService } from './app.service'; require('dotenv').config() @Module({ imports: [ ConfigModule.forRoot() ], controllers: [AppController], providers: [AppService], }) export class AppModule {}
Al módulo de Configuration, le vamos a añadir algunos parámetros como puede ser la ruta donde vamos a cargar las variables de entorno, pero dependerá de que entorno nosotros le indiquemos.
Para eso, en la raíz del proyecto, creamos un fichero llamado .env, que es un fichero que gracias a dotenv cargará las variables que le indiquemos.
El contenido del fichero .env será el siguiente:
NODE_ENV=development
Volvemos al fichero app.module y añadimos la propiedad envFilePath al módulo Configuration.
import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import { AppController } from './app.controller'; import { AppService } from './app.service'; require('dotenv').config() @Module({ imports: [ ConfigModule.forRoot({ envFilePath: `./env/${process.env.NODE_ENV}.env`, }) ], controllers: [AppController], providers: [AppService], }) export class AppModule {}
Con process.env, podemos recoger las variables de entorno. En este caso, recogemos el valor de NODE_ENV para saber si estamos en desarrollo o producción.
Ahora, debemos crearnos una carpeta env con varios ficheros .env donde el nombre de cada uno debe ser el nombre de cada entorno.
En cada fichero env debemos tener las mismas variables pero con diferentes valores. Por ejemplo:
Nos falta poder procesar estas variables para poder recogerlas desde la configuración de NestJS.
Para ello, nos crearemos un fichero llamado configuration en una carpeta llamada configuration con el siguiente contenido:
import { registerAs } from "@nestjs/config"; export default registerAs('example', () => ({ }))
Este registerAs, es una función especial de la configuración de NestJS donde le indicamos un nombre (example) y que subvariables cuelgan de este.
import { registerAs } from "@nestjs/config"; export default registerAs('example', () => ({ variable1: process.env.VARIABLE1, variable2: process.env.VARIABLE2 }))
Por defecto, todas las variables son cadenas, si alguna fuera un numero, tendríamos que parsearla. Por ejemplo:
import { registerAs } from "@nestjs/config"; export default registerAs('example', () => ({ variable1: process.env.VARIABLE1, variable2: process.env.VARIABLE2, variable3: parseInt(process.env.VARIABLE3) }))
En app.module, tenemos que asociar este fichero configuration al modulo de configuración, con el parámetro load del módulo.
import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import { AppController } from './app.controller'; import { AppService } from './app.service'; import configuration from './configuration/configuration'; require('dotenv').config() @Module({ imports: [ ConfigModule.forRoot({ load: [configuration], envFilePath: `./env/${process.env.NODE_ENV}.env`, }) ], controllers: [AppController], providers: [AppService], }) export class AppModule {}
Con esto, ya podemos usar el servicio que nos proporciona el módulo configuration para recoger estos valores.
Vamos a crear un módulo de ejemplo, si no recuerdas como se crea un módulo, aquí te lo explico:
Así se quedará nuestro app.module:
import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import { AppController } from './app.controller'; import { AppService } from './app.service'; import configuration from './configuration/configuration'; import { ExampleModule } from './modules/example/example.module'; require('dotenv').config() @Module({ imports: [ ConfigModule.forRoot({ load: [configuration], envFilePath: `./env/${process.env.NODE_ENV}.env`, }), ExampleModule ], controllers: [AppController], providers: [AppService], }) export class AppModule {}
Si queremos usar la configuración en el nuevo módulo, tendríamos que importarlo, pero tenemos una forma más cómoda y es haciendo la configuración global, de esta forma no es necesario importar el módulo de configuración de NestJS en otros módulos. Se hace añadiendo la propiedad isGlobal al módulo de configuration.
import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import { AppController } from './app.controller'; import { AppService } from './app.service'; import configuration from './configuration/configuration'; import { ExampleModule } from './modules/example/example.module'; require('dotenv').config() @Module({ imports: [ ConfigModule.forRoot({ load: [configuration], envFilePath: `./env/${process.env.NODE_ENV}.env`, isGlobal: true }), ExampleModule ], controllers: [AppController], providers: [AppService], }) export class AppModule {}
En el servicio ExampleService, vamos a recuperar estas variables. Para ello, inyectamos el servicio ConfigService en el constructor y con la función get, colocaremos la ruta de la variable a obtener.
Recuerda que en el fichero configuration, pusimos «example» y variables que colgaban de este, entonces por ejemplo si queremos coger la variable1, la ruta seria example.variable1.
import { Injectable } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; @Injectable() export class ExampleService { constructor(private configService: ConfigService){ console.log(this.configService.get('example.variable1')); console.log(this.configService.get('example.variable2')); console.log(this.configService.get('example.variable3')); } }
Si ejecutamos la aplicación, veremos los valores:
Si vamos al fichero .env y cambiamos a production.
Vemos que ha cambiado, con esto ya tendríamos la configuración ya montada.
Espero que os sea de ayuda. Si tenéis dudas, preguntad. Estamos para ayudarte.
Funciona pero al momento de crear la conexión a la base de datos con sequelize es necesario setear los valores dentro de el .env, por lo tanto esta solución no funciona ahí.