É muito comum em projetos de software web que existam configurações para que a aplicação funcione como a porta HTTP, chaves de API e outras. Mais comum ainda é que tais configurações possuam divergências entre os ambientes de desenvolvimento, testes e produção. Por causa disso, tais configurações não devem ser escritas diretamente no código das aplicações, o que chamamos de “hard code”, mas sim definidas em variáveis/configurações de ambiente.
Estas variáveis de ambiente podem ser configuradas diretamente no PATH do SO com comandos como SET, o que é bem comum em ambientes produtivos, mas também podem ser utilizados arquivos .env para isso, principalmente em ambientes de desenvolvimento. No entanto, não basta ter um arquivo .env solto no seu projeto com as suas variáveis dentro para que elas passem a existir na sua aplicação, você tem de carregá-las.
No tutorial de hoje eu vou lhe ensinar como configurar o seu projeto NestJS para usar variáveis de ambiente. Obviamente parto do pressuposto que você já sabe o básico de NestJS, mas se não souber, comece por este outro tutorial aqui.
Vamos lá!
#1 – Setup do Projeto
Vamos começar criando um novo projeto NestJS, com o comando abaixo.
1 2 3 |
npx @nestjs/cli new dotenv-example |
Agora vamos instalar a dependência que vamos precisar.
1 2 3 |
@nestjs/config |
O próximo passo é criar seu arquivo .env na raiz do projeto, com as variáveis que você precisa e que variam enormemente de projeto para projeto. Abaixo, coloco apenas dois exemplos que já usei e que são comuns.
1 2 3 4 |
PORT=3000 DATABASE_URL=mongodb://localhost:27017/mydatabase |
Recomendo que inclua o arquivo .env no arquivo .gitignore do seu projeto, que deve ficar na raiz do projeto, se ainda não existir.
1 2 3 |
.env |
E outra dica inclui você criar um arquivo .env.example, na raiz do projeto também, explicando as variáveis usadas no projeto e para que elas servem, como abaixo.
1 2 3 4 5 6 7 |
# Your backend HTTP port. Ex: 3000 PORT= # Your MongoDB connection string. Ex: mongodb://localhost:27017/mydatabase DATABASE_URL= |
Não é obrigatório, mas ajuda na hora de fazer setup do projeto em uma nova máquina.
#2 – Usando as Configurações
Para usar as variáveis presentes no .env, o primeiro passo é carregá-lo para a memória da aplicação. Isso deve ser feito no seu módulo principal, geralmente chamado de AppModule, em app.module.ts. Comece importando a biblioteca que instalamos como abaixo.
1 2 3 |
import {ConfigModule} from "@nestjs/config"; |
Depois, importe esse módulo no módulo principal, na diretiva imports de inicialização dele, usando a função forRoot que procura o arquivo .env na raiz do projeto e carrega todas variáveis para memória.
1 2 3 4 5 6 7 8 |
@Module({ imports: [ConfigModule.forRoot()], controllers: [AppController], providers: [AppService], }) export class AppModule {} |
Se você futuramente tiver outros imports neste módulo, não esqueça de deixar esse como sendo o primeiro sempre, para que as variáveis sejam carregadas antes dos demais módulos.
Agora você está livre para usar as variáveis de ambiente normalmente como faria com Node.js, usando process.env.NOME_VARIAVEL, como abaixo, onde estou subindo o servidor do NestJS na porta definida no .env (esse código fica no main.ts).
1 2 3 4 5 6 7 8 9 10 |
import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; async function bootstrap() { const app = await NestFactory.create(AppModule); await app.listen(process.env.PORT); } bootstrap(); |
Opcionalmente, pode ser interessante criar um módulo que mapeie e tipe corretamente as variáveis de ambiente, como no arquivo configs.ts que exemplifico abaixo. Repare como inclusive consigo fazer transformações e até definir fallbacks caso alguma variável de ambiente não tenha sido preenchida.
1 2 3 4 5 6 7 8 9 10 |
const DATABASE_URL: string = `${process.env.DATABASE_URL}`; const PORT: number = parseInt(`${process.env.PORT || 3000}`); export default { DATABASE_URL, PORT } |
Eu poderia também ter colocado validações e mais, mas acho que você entendeu a ideia. Agora, posso usar esse módulo no meu código original, da seguinte forma.
1 2 3 4 5 6 7 8 9 10 11 |
import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; import Configs from "./configs"; async function bootstrap() { const app = await NestFactory.create(AppModule); await app.listen(Configs.PORT); } bootstrap(); |
Mas Luiz, e se eu precisar usar variáveis de ambiente para configurar módulos importados já no AppModule, isso vai me atender?
Exemplo abaixo, onde eu preciso usar uma variável de ambiente já pra configurar o módulo de email:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
@Module({ imports: [ ConfigModule.forRoot(), MailerModule.forRoot({ transport: process.env.MAILER_TRANSPORT, defaults: { secure: false, from: process.env.DEFAULT_FROM } }) ], controllers: [AppController], providers: [AppService], }) export class AppModule { } |
Pelas minhas experiências, não funciona. Nesse caso, se você precisa usar variáveis de ambiente já nos imports do AppModule, elas não vão estar prontas ainda. Neste caso, você pode instalar o pacote DotEnv normalmente e fazer o config dele no main.ts bem no topo e imediatamente na linha abaixo elas vão estar disponíveis.
E com isso finalizo mais este tutorial, espero que você tenha gostado.
Até a próxima!
Olá, tudo bem?
O que você achou deste conteúdo? Conte nos comentários.