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)