deividy@blog:~

3 formas de passar configurações para uma app em Node.js

14/02/2018

Hard code? Config file? Environment variables? HELP!?

3 formas de passar configurações para uma app em Node.js


Falaae #codingninja! :D
Vamos ver aqui as 3 formas mais comuns de passar, ou usar, configs em uma app escrita em Node.js:


1. Hard code

Hard code é provavelmente a forma mais 'suja' de fazer isso, basicamente consiste em você escrever em algum ponto aleatório de sua app as configs dela, não importa se você deixa comentado bonitinho, ainda será a mais suja e vai ficar cada vez mais difícil de escalar, um simples exemplo:

// ... const { Client } = require('pg'); // configs { const httpPort = 9000; const saltRounds = 4; const jwtSecret = 'SECRET! #codeinaction #tmj :D'; const psqlConfig = 'postgres://localhost:5432/codeinaction_login_area'; // } <-- configs const app = express(); // ...

Consegue ver problemas caso usemos um ambiente para dev e outro para prod? Teriamos que colocar alguns ifs malucos aí no meio e o pior poderia ser quando um novo dev entrar para o time, não faça isso para uma app do mundo real!



2. Arquivo de configuração

Outra forma comum de passar configurações é o uso de arquivos específicos de configuração, essa é uma maneira mais limpa que hard code e pode até ser usada para apps em produção desde que seja feito com prudência (e amor e carinho :)).

Um arquivo de configuração pode ser tanto um .js ou .json, aconselho o uso do JavaScript ao invés de JSON pois nesse caso não precisamos nos preocupar com a formatação exata do JSON e ainda podemos usar alguma lógica ali dentro (mas cuidado! não coloque lógicas em arquivos de configurações! Porém, alguma vezes podemos precisar de lógicas bem simples ou até mesmo do uso de vars como __dirname, nesses casos é aceitável e o JS te da um vantagem.)


Um config.js, geralmente se parecerá com isso:

module.exports = { publicPath: `${__dirname}/public`, dbConfig: { user: 'foo', password: 'bar', database: 'codeinaction' } }

Podemos usar arquivos de configurações basicamente de duas formas:


1) Pré configurando uma lista de ambientes e arquivos de configurações.

2) Passando na command line de inicio do app o caminho para o arquivo de configurações.


Da primeira forma podemos fazer algo como:

const configPath = process.env.NODE_ENV === 'PROD' ? 'config.prod' : 'config.local'; const config = require(configPath);

Ou um pouco mais limpo e com mais opções:

function getConfigPath () { switch (process.env.NODE_ENV) { case 'prod': return 'config.prod'; case 'local': return 'config.local'; case 'dev': return 'config.dev'; } throw new Error(`Unknown env ${process.env.NODE_ENV}`); } const config = require(getConfigPath());

Curiosidade: em ambos os casos estamos usando env vars, você não precisa necessariamente usá-las para carregar o arquivo de config, mas nesse caso você terá que achar outro jeito de identificar o ambiente, o que nos leva a segunda forma de usar arquivos de configurações.


Passar o path do arquivo de configuração é uma forma ainda mais limpa de passar a config para sua app, evita ifs no código e você pode mover o arquivo de configuração para onde quiser.

Para usar essa tática, vamos usar o process.argv, podemos tanto usar ele direto e parsearmos na mão os args, ou podemos usar algum módulo de forma que podemos passar facilmente um -c configPath.


Vamos ver um simples exemplo usando o minimist:

const argv = require('minimist')(process.argv.slice(2)); const config = require(argv.c);

A usage ficaria assim:

node app.js -c /my-config-path/is-here/config.local.js

Mais fácil, né?



3. Variáveis de Ambiente

Variável de ambiente se tornou um padrão na comunidade Node.js, principalmente com o surgimento de containers como o Docker.

Definição de variável de ambiente segundo Wikipedia: "Variável de ambiente é uma variável de um sistema operacional que geralmente contém informações sobre o sistema, caminhos de diretórios específicos no sistema de arquivos e as preferências do utilizador. Ela pode afetar a forma como um processo se comporta, e cada processo pode ler e escrever variáveis de ambiente".


Na construção de containers, fica mais fácil simplesmente passar as variáveis de ambiente do que ter que se preocupar com command line ou arquivos de configuração, outra vantagem é que você pode tanto usar algum modulo (como o dotenv) para carregar um arquivo chamado .env ou definir diretamente no seu ambiente.


Uma prática comum para o uso de env vars é comitarmos no repo um file chamado .env.sample, com um exemplo de todas as variáveis que tem que ser configurada e deixar no .gitignore o .env, dessa forma, todo dev que for trabalhar no projeto ou ambiente que for configurado, basta copiarmos esse file e editar para as configurações específicas.


Um .env file se parece com:

DB_HOST=localhost DB_USER=root DB_PASS=s1mpl3

E caso você esteja usando o dotenv, a única coisa que você vai ter que fazer para carregar esse arquivo vai ser:

require('dotenv').config()

That's it!

Caso você não queira usar um arquivo, você pode definir as vars diretamente, em um sistema UNIX (OSX/Linux), basta você mandar diretamente no console:

export DB_HOST=localhost export DB_USER=root export DB_PASS=s1mpl3

Porém, dessa forma as variáveis ficam disponíveis apenas para a sessão atual, caso você feche a janela ou reinicie, elas vão sumir, você ainda pode colocar elas em seu .bashrc


Todas as variáveis de ambiente ficam disponíveis no Node.js pelo process.env, exemplo:

db.connect({ host: process.env.DB_HOST, username: process.env.DB_USER, password: process.env.DB_PASS })

São essas as opções para passar configs para o Node.



Tem alguma outra forma que não citei aqui? Prefere env vars a config files? Você é um vida loka que usa hard coded?


Comenta ae, vamos trocar uma idéia :)