Finalmente consegui finalizar meu primeiro post para o dev.to
Nas primeiras tentativas de entregar algo eu falhei miseravelmente pois, simplesmente, a postagem ficava gigantesca demais.
Dessa vez consegui deixar o escopo fechadinho e de uma maneira que, acredito eu, seja bem fácil de reproduzir.
Então, chega de falatório (ou escritório...) e vamos começar.
⚡ Pré requisitos
Não vamos criar nada revolucionário ou complexo demais por aqui, já que o intuito é demonstrar como validar as variáveis necessárias para a aplicação subir.
Para este tutorial, vamos precisar do Node.js
instalado na máquina. Também vou usar o git
para versionar os códigos. Vou partir do princípio de que estes pré-requisitos já estejam atendidos por você, caro leitor.
Estou utilizando o macOS como sistema operacional e utilizarei o terminal para executar todos os comandos. Se estiver usando Windows, sugiro fortemente que utilize o WSL.
Também estou usando o yarn
como gerenciador de pacote ao invés do npm
.
⚡ Tudo que vamos usar nesse projeto
- typescript
- fastify
- dotenv
- zod
- tsx
- tsup
Um detalhe: estou usando o fastify
pois vou postar mais alguns materiais por aqui usando esse micro-framework. Mas o que vou aplicar aqui é totalmente compatível com o express
ou com frameworks mais parrudos, como o NestJS
.
⚡ Iniciando o projeto
Vamos iniciar criando um novo diretório env-validate
.
Abra o terminal e execute o comando:
mkdir env-validate && \
cd env-validate
Agora vamos iniciar um projeto node com o comando:
yarn init -y
Já preparando para que os commits no git não suba o diretório node_modules
e o .env
, vamos criar um arquivo .gitignore
na raiz do projeto:
touch .gitignore && \
echo '.env' >> .gitignore && \
echo 'node_modules' >> .gitignore
Vamos fazer um primeiro commit para facilitar a navegação no histórico de versões no futuro.
git add . && \
git commit -m "initial commit"
⚡ Iniciando o Fastify e o Typescript
Vamos iniciar um servidor usando o fastify
com uma rota GET /hello
para termos um mínimo de código por aqui.
Para isso vamos instalar o fastify
:
yarn add fastify
Como vamos usar Typescript, vamos precisar do próprio typescript instalado.
Também vamos precisar instalar a tipagem do node (@types/node), um interpretador para os arquivos .ts
(tsx) e um compilador de typescript para javascript (tsup).
yarn add -D typescript @types/node tsx tsup
Com o typescript instalado, vamos iniciar o tsconfig.json
com o comando:
yarn tsc --init
Para este tutorial não vamos precisar modificar nada neste arquivo
Agora vamos gerar o arquivo app.ts
, onde as configurações do fastify
estarão:
mkdir -p src/infra && \
touch src/infra/app.ts
Cole o conteúdo abaixo no arquivo app.ts
gerado:
import fastify, { FastifyReply, FastifyRequest } from "fastify";
const app = fastify()
app.get('/hello', (request: FastifyRequest, reply: FastifyReply) => {
return reply.status(200).send({ message: 'hello world' })
})
export { app }
O código deste arquivo criamos uma constante app
que é uma instância da função fastify
.
Com essa variável app
, criamos uma rota GET /hello
que retornará uma mensagem 'hello world' com status 200.
Agora vamos gerar o arquivo server.ts
, que é o nosso entrypoint da aplicação
touch src/infra/server.ts
Cole o conteúdo abaixo no arquivo server.ts
:
import { app } from "./app";
async function bootstrap() {
await app.listen({ host: '0.0.0.0', port: 3333 })
console.log('🚀 server started at port 3333')
}
bootstrap()
Explicando...
Aqui temos uma função assíncrona bootstrap
que cria um servidor fastify
que veio da variável 'app' importada na primeira linha.
Este servidor está subindo no endereço http://localhost:3333
Mas para este servidor funcionar, precisamos inserir um script no arquivo package.json
.
Abra este arquivo e insira uma nova chave scripts
:
"scripts": {
"start:dev": "tsx watch src/infra/server.ts"
}
Para subir o servidor, basta no terminal executar o comando:
yarn start:dev
O que esperamos ver no terminal é a seguinte mensagem:
Uma vez visto a bela mensagem de start do servidor, basta acessar via browser o endereço: http://localhost:3333/hello
Se tudo estiver certo, esta é a mensagem que deverá ver no seu browser
Para ver a mensagem formatada assim, estou usando a extensão JSON Viewer
com tema dark no Chrome
Novo commit para finalizar esse bloco
git add . && \
git commit -m "fastify server started"
⚡ Validando as variáveis de ambiente
Se ainda estiver com o servidor executando no terminal, encerre o processo com CTRL + C
ou abra uma nova aba/janela.
Agora vamos gerar um arquivo .env
onde listaremos quais variáveis de ambiente são necessárias para a aplicação iniciar.
touch .env
Cole o conteúdo abaixo no arquivo .env
gerado:
# API_PORT=3333
Para validar as variáveis de ambiente, vamos utilizar a biblioteca de validação zod e também vamos precisar instalar a biblioteca dotenv. Esta última nos possibilita ler as variáveis de ambiente ao importá-la no início do arquivo env.ts
.
Execute no terminal:
yarn add zod dotenv
Para criar o arquivo env.ts
, execute:
touch src/infra/env.ts
Cole o conteúdo abaixo no arquivo gerado:
import 'dotenv/config'
import { z } from 'zod'
const envSchema = z.object({
API_PORT: z.coerce.number()
})
const getEnv = envSchema.safeParse(process.env)
if (!getEnv.success) {
const errorMessage = 'load environment failed'
console.error(errorMessage, getEnv.error.format())
throw new Error(errorMessage)
}
export const env = getEnv.data
Vamos repassar o que foi colado:
Primeiro, importamos o dotenv/config
para realizar a leitura do arquivo .env
. Em seguida importamos de dentro do zod
o z.
O zod trabalha com uma série de parâmetros e aqui estamos usando o object
para gerar um schema
com as variáveis necessárias para a aplicação iniciar.
Neste caso declaramos que a propriedade API_PORT
é do tipo z.coerce.number()
.
Tudo que é importado das variáveis de ambiente do arquivo .env
é interpretado como texto. O termo coerce
utilizando antes do .number()
é uma forma de dizer para o zod
realizar uma conversão do que está chegando (string) para o formato number
.
Em seguida criamos uma variável getEnv
onde passamos o envSchema.safeParse(process.env)
O comando safeParse
valida se o que está sendo repassado pelo process.env
atende ao que foi especificado no schema
.
Como resultado, a variável getEnv
terá uma propriedade .success
booleana.
Logo abaixo estamos checando se este .success
falhou e, caso tenha falhado, interrompemos o script com um erro load environment failed
.
Se a validação passar, ou seja, se o .success
for verdadeiro, exportamos a variável env
com os dados obtidos do getEnv.data
Chegou a hora de testar:
Volte ao arquivo server.ts
e mude a propriedade port
para que este leia o env.API_PORT
exportado nos passos anteriores.
o arquivo server.ts
ficará assim
import { app } from "./app";
import { env } from "./env";
async function bootstrap() {
await app.listen({ host: '0.0.0.0', port: env.API_PORT })
console.log(`🚀 server started at port ${env.API_PORT}`)
}
bootstrap()
Aproveitei e também modifiquei a mensagem do console para que a porta passada nas variáveis seja exibida no terminal.
Agora vamos rodar a aplicação para ver o que acontece:
yarn start:dev
E... eitaaaa, erro!
Calma, era o esperado :)
Como pode observar no terminal, temos a seguinte mensagem de erro no topo da execução:
Essa mensagem está aqui porque criamos o nosso arquivo .env
com a variável API_PORT
comentada de propósito.
Para resolver isso, pare a execução do servidor com CTRL + C
, volte no arquivo .env
e remova o # da primeira linha.
Seu arquivo .env.
deve ficar assim:
API_PORT=3333
Execute a aplicação novamente e tudo deve dar certo agora
yarn start:dev
O esperado é você ver o seu terminal com a mensagem:
Tenho certeza (será?) que tudo deu certo.
Então vamos criar um novo arquivo .env.example
para que, ao clonar este repositório, seja possível iniciar o projeto apenas renomeando para .env
cp .env .env.example
E, por último nessa sessão, vamos commitar a coisa toda e partir para a última parte.
git add . && \
git commit -m "environment variables validated"
⚡ Gerando build do projeto
Para finalizar este tutorial, vamos configurar o script que executará o build da aplicação
e o start
da versão final em javascript.
Para isso, vá até o arquivo package.json
e adicione os scripts abaixo:
"scripts": {
...
"prebuild": "tsc --noEmit",
"build": "tsup src --out-dir build",
"start": "node build/server.js"
}
Explicando mais uma vez...
O script build
utiliza a biblioteca tsup
para transpilar os códigos typescript para javascript usando como diretório build
como saída.
Porém, antes de executar o transpile, o prebuild
é chamado automaticamente para que o typescript faça o transpile por conta própria apenas em memória. Caso algo falhe, o build é interrompido nessa fase.
Se nada falhar, o diretório build
é populado com os arquivos javascript nos quais o Node.JS será capaz de executar nativamente.
O script start
executa o servidor já com o arquivo compilado.
Este é o comando que será utilizado caso esta aplicação esteja publicada.
Para testar tudo, basta executar no terminal:
yarn build
Você deverá ver algo como:
Agora basta executar:
yarn start
E verá no seu terminal...
Novo commit e fim do tutorial
git add . && \
git commit -m "app build added"
Ufaaa...
Assim encerro meu primeiro tutorial postado por aqui.
Toda e qualquer variável de ambiente necessária para a aplicação poderá ser listada no schema gerado no arquivo env.ts
.
Dessa forma, caso alguma delas não seja declarada no ambiente onde a aplicação será publicada.
Por exemplo: variáveis do banco de dados, da AWS ou de qualquer outro provider, variáveis de tokens JWT e por aí vai.
Basta adicionar o que precisa no schema e está garantido que a aplicação se quer irá iniciar na falta de alguma delas.
Espero que tenham gostado.
Para acessar o repositório do projeto no github, clique aqui
Até o próximo ;)
Top comments (0)