Variáveis de ambiente
As variáveis de ambiente servem para armazenar segredos como a senha do banco de dados, o segredo do aplicativo ou uma chave de API fora da base de código do seu aplicativo.
Além disso, as variáveis de ambiente podem ser usadas para ter configurações diferentes para ambientes diferentes. Por exemplo, você pode usar um mailer de memória durante os testes, um mailer SMTP durante o desenvolvimento e um serviço de terceiros na produção.
Como as variáveis de ambiente são suportadas por todos os sistemas operacionais, plataformas de implantação e pipelines de CI/CD, elas se tornaram um padrão de fato para armazenar segredos e configurações específicas do ambiente.
Neste guia, aprenderemos como aproveitar as variáveis de ambiente dentro de um aplicativo AdonisJS.
Lendo variáveis de ambiente
O Node.js expõe nativamente todas as variáveis de ambiente como um objeto por meio da propriedade global process.env
, e você pode acessá-las da seguinte forma.
process.env.NODE_ENV
process.env.HOST
process.env.PORT
Usando o módulo env do AdonisJS
A leitura de variáveis de ambiente por meio do objeto process.env
não requer configuração no lado do AdonisJS, pois o tempo de execução do Node.js o suporta. No entanto, no restante deste documento, usaremos o módulo env do AdonisJS pelos seguintes motivos.
- Capacidade de armazenar e analisar variáveis de ambiente de vários arquivos
.env
. - Validar variáveis de ambiente assim que o aplicativo iniciar.
- Ter segurança de tipo estático para variáveis de ambiente validadas.
O módulo env é instanciado dentro do arquivo start/env.ts
, e você pode acessá-lo em outro lugar dentro do seu aplicativo da seguinte forma.
import env from '#start/env'
env.get('NODE_ENV')
env.get('HOST')
env.get('PORT')
// Retorna 3333 quando PORT não está definido
env.get('PORT', 3333)
Compartilhando o módulo env com modelos Edge
Se você quiser acessar variáveis de ambiente dentro de modelos Edge, então você deve compartilhar o módulo env
como uma variável global com modelos Edge.
Você pode criar view.ts
como um arquivo de pré-carregamento dentro do diretório start
e escrever as seguintes linhas de código dentro dele.
// start/view.ts
import env from '#start/env'
import edge from 'edge.js'
edge.global('env', env)
Validando variáveis de ambiente
As regras de validação para variáveis de ambiente são definidas dentro do arquivo start/env.ts
usando o método Env.create
.
A validação é realizada automaticamente quando você importa este arquivo pela primeira vez. Normalmente, o arquivo start/env.ts
é importado por um dos arquivos de configuração do seu projeto. Caso contrário, o AdonisJS importará esse arquivo implicitamente antes de inicializar o aplicativo.
O método Env.create
aceita o esquema de validação como um par chave-valor.
- A chave é o nome da variável de ambiente.
- O valor é a função que executa a validação. Pode ser uma função inline personalizada ou uma referência a métodos de esquema predefinidos como
schema.string
ouschema.number
.
import Env from '@adonisjs/core/env'
/**
* A raiz do aplicativo é usada para localizar arquivos .env dentro
* da raiz do projeto.
*/
const APP_ROOT = new URL('../', import.meta.url)
export default await Env.create(APP_ROOT, {
HOST: Env.schema.string({ format: 'host' }),
PORT: Env.schema.number(),
APP_KEY: Env.schema.string(),
APP_NAME: Env.schema.string(),
CACHE_VIEWS: Env.schema.boolean(),
SESSION_DRIVER: Env.schema.string(),
NODE_ENV: Env.schema.enum([
'development',
'production',
'test'
] as const),
})
Informações de tipo estático
As mesmas regras de validação são usadas para inferir as informações de tipo estático. As informações de tipo estão disponíveis ao usar o módulo env.
API de esquema do validador
schema.string
O método schema.string
garante que o valor seja uma string válida. Strings vazias falham na validação, e você deve usar a variante opcional para permitir strings vazias.
{
APP_KEY: Env.schema.string()
}
// Marque APP_KEY como opcional
{
APP_KEY: Env.schema.string.optional()
}
O valor da string pode ser validado para sua formatação. A seguir está a lista de formatos disponíveis.
host
Valida o valor para ser uma URL válida ou um endereço IP.
{
HOST: Env.schema.string({ format: 'host' })
}
url
Valida o valor para ser uma URL válida. Opcionalmente, você pode tornar a validação menos rigorosa permitindo que URLs não tenham protocol
ou tld
.
{
S3_ENDPOINT: Env.schema.string({ format: 'url' })
// Permitir URLs sem protocolo
S3_ENDPOINT: Env.schema.string({ format: 'url', protocol: false })
// Permitir URLs sem tld
S3_ENDPOINT: Env.schema.string({ format: 'url', tld: false })
}
email
Valida o valor para ser um endereço de e-mail válido.
{
SENDER_EMAIL: Env.schema.string({ format: 'email' })
}
schema.boolean
O método schema.boolean
garante que o valor seja um booleano válido. Valores vazios falham na validação, e você deve usar a variante opcional para permitir valores vazios.
As representações de string de 'true'
, '1'
, 'false'
e '0'
são convertidas para o tipo de dados booleano.
{
CACHE_VIEWS: Env.schema.boolean()
}
// Marque como opcional
{
CACHE_VIEWS: Env.schema.boolean.optional()
}
schema.number
O método schema.number
garante que o valor seja um número válido. A representação de string de um valor numérico é convertida para o tipo de dados numérico.
{
PORT: Env.schema.number()
}
// Marque como opcional
{
PORT: Env.schema.number.optional()
}
schema.enum
O método schema.enum
valida a variável de ambiente em relação a um dos valores predefinidos. As opções de enumeração podem ser especificadas como uma matriz de valores ou um tipo de enumeração nativo do TypeScript.
{
NODE_ENV: Env
.schema
.enum(['development', 'production'] as const)
}
// Marque como opcional
{
NODE_ENV: Env
.schema
.enum
.optional(['development', 'production'] as const)
}
// Usando enumerações nativas
enum NODE_ENV {
development = 'development',
production = 'production'
}
{
NODE_ENV: Env.schema.enum(NODE_ENV)
}
Funções personalizadas
As funções personalizadas podem executar validações não cobertas pela API do esquema.
A função recebe o nome da variável de ambiente como o primeiro argumento e o valor como o segundo argumento. Ela deve retornar o valor final após a validação.
{
PORT: (name, value) => {
if (!value) {
throw new Error('Value for PORT is required')
}
if (isNaN(Number(value))) {
throw new Error('Value for PORT must be a valid number')
}
return Number(value)
}
}
Definindo variáveis de ambiente
Em desenvolvimento
As variáveis de ambiente são definidas dentro do arquivo .env
durante o desenvolvimento. O módulo env procura esse arquivo na raiz do projeto e o analisa automaticamente (se existir).
# .env
PORT=3333
HOST=0.0.0.0
NODE_ENV=development
APP_KEY=sH2k88gojcp3PdAJiGDxof54kjtTXa3g
SESSION_DRIVER=cookie
CACHE_VIEWS=false
Em produção
É recomendável usar sua plataforma de implantação para definir as variáveis de ambiente na produção. A maioria das plataformas de implantação modernas tem suporte de primeira classe para definir variáveis de ambiente a partir de sua IU da web.
Suponha que sua plataforma de implantação não forneça meios para definir variáveis de ambiente. Você pode criar um arquivo .env
na raiz do projeto ou em algum local diferente em seu servidor de produção.
O AdonisJS lerá automaticamente o arquivo .env
da raiz do projeto. No entanto, você deve definir a variável ENV_PATH
quando o arquivo .env
for armazenado em algum local diferente.
# Tenta ler o arquivo .env da raiz do projeto
node server.js
# Lê o arquivo .env do diretório "/etc/secrets"
ENV_PATH=/etc/secrets node server.js
Durante os testes
As variáveis de ambiente específicas para o ambiente de teste devem ser definidas dentro do arquivo .env.test
. Os valores deste arquivo substituem os valores do arquivo .env
.
// .env
NODE_ENV=development
SESSION_DRIVER=cookie
ASSETS_DRIVER=vite
// .env.test
NODE_ENV=test
SESSION_DRIVER=memory
ASSETS_DRIVER=fake
// Durante os testes
import env from '#start/env'
env.get('SESSION_DRIVER') // memória
Todos os outros arquivos dot-env
Juntamente com o arquivo .env
, o AdonisJS processa as variáveis de ambiente dos seguintes arquivos dot-env. Portanto, você pode opcionalmente criar esses arquivos (se necessário).
O arquivo com a classificação mais alta substitui os valores dos arquivos de classificação mais baixa.
Classificação | Nome do arquivo | Notas |
---|---|---|
1º | .env.[NODE_ENV].local | Carregado para o NODE_ENV atual. Por exemplo, se o NODE_ENV estiver definido como development , o arquivo .env.development.local será carregado. |
2º | .env.local | Carregado em todos os ambientes, exceto os ambientes test e testing |
3º | .env.[NODE_ENV] | Carregado para o NODE_ENV atual. Por exemplo, se o NODE_ENV estiver definido como development , o arquivo .env.development será carregado. |
4º | .env | Carregado em todos os ambientes. Você deve adicionar este arquivo a .gitignore ao armazenar segredos dentro dele. |
Usando variáveis dentro dos arquivos dot-env
Dentro dos arquivos dot-env, você pode referenciar outras variáveis de ambiente usando a sintaxe de substituição de variáveis.
Calculamos o APP_URL
das propriedades HOST
e PORT
no exemplo a seguir.
HOST=localhost
PORT=3333
URL=$HOST:$PORT
Todas as letras, números e o sublinhado (_) após o sinal $
são usados para formar um nome de variável. Você deve envolver o nome da variável entre chaves {}
se o nome tiver caracteres especiais diferentes de um sublinhado.
REDIS-USER=admin
REDIS-URL=localhost@${REDIS-USER}
Escapando o sinal $
Para usar o sinal $
como um valor, você deve escapá-lo para evitar a substituição de variáveis.
PASSWORD=pa\$\$word