Backend
Configuração do runtime
Ambiente de execução: NodeJS v16.15.0 (Recomendado usar NVM caso você já tenha uma versão do Node instalada)
Gerenciador de pacotes: NPM v8.10.0.
Dependências externas
É necessária uma string de conexão com um banco de dados PostgreSQL v14.3. Para o ambiente de desenvolvimento, é recomendada a utilização de um container PostgreSQL no Docker. Outra alternativa para utilizar o PostgreSQL tem instalar nada localmente, é criar um projeto no Heroku com um banco PostgreSQL, e utilizar a string fornecida por eles.
Variáveis de ambiente
DATABASE_URL
: string de conexão com o banco de dados seguindo o formato exigido pelo Prisma.
JWT_SECRET_KEY
: chave secreta gerada aleatóriamente utilizada para gerar JWT's. Caso esteja utilizando um ambiente Linux, é possível gerar uma string aleatória de 32 dígitos hexadecimais com o seguinte comando:
openssl rand -hex 32
JWT_EXPIRES_IN
: tempo de duração do JWT em segundos ou uma string no formato zeit/ms.
JWT_ALGORITHM
: algoritmo para criptografar o JWT. Opções disponíveis.
PORT
: porta utilizada para o servidor.
SECURITY_UP
: indica se a autenticação está ativada. Caso esteja desativada, toda requisição estará autenticada com um usuário coringa.
Ambientes de desenvolvimento e produção
Após definir as variáveis de ambiente e clonar o repositório, execute o seguinte comando para instalar as dependências:
npm i
Ambiente de desenvolvimento
Configurando variáveis de ambiente
Crie um arquivo na raíz do repositório, chamado .env
, e copie o conteúdo do arquivo .env.example
nesse arquivo, e preencha os valores das variáveis de acordo com a descrição fornecida na seção Variáveis de ambiente.
Scripts
Para executar as migrações no banco de dados, utilize o seguinte comando:
npx prisma migrate dev
Para popular o banco de dados com dummy data utilize o seguinte comando:
npx prisma db seed
PS.: Os dados estão disponíveis em prisma/seed.ts
Para iniciar o servidor de desenvolzvimento, utilize o seguinte comando:
npm run dev
Ambiente docker (necessário conhecimento básico de docker compose)
Configurando variáveis de ambiente
As variáveis de ambiente utilizadas serão as que estão declaradas no arquivo .env.docker
.
No ambiente docker, existe uma variável de ambiente chamada COMPOSE_PROJECT_NAME
(entenda mais).
Essa variável é utilizada como prefixo para o nome dos serviços que serão criados no docker compose. O valor padrão dessá variável é igual ao nome do diretório atual. É recomendado definir o valor dessa variável no arquivo .env.docker
para que os serviços sejam criados com nomes únicos. Ao definir o valor dessa variável (ou utilizar o valor padrão), certifique-se de que os scripts estejam utilizando os nomes corretos.
Ex.: Se o valor de COMPOSE_PROJECT_NAME
for my-project
, então o valor padrão dessa variável será my-project
, portanto, os scripts devem ser alterados para
docker exec my-project-web-1 ...
Atenção ao definir o valor da variável DATABASE_URL
: O host da URL deve ser o nome do serviço declarado no arquivos docker-compose.yml
.
Ex.: No arquivo docker-compose.yml
foi utilizado o nome banco_de_dados
como nome do serviço do PostgreSQL. Logo, o valor da variável DATABASE_URL
deve ser: postgresql://postgres:postgres@banco_de_dados:5432/saude_bucal_backend?schema=public
. Entenda redes no docker compose.
Scripts
Para iniciar o servidor utilize o seguinte comando:
npm run docker
Atenção: Para executar qualquer comando que inicie com docker:db-*
, é necessário que o serviço web
esteja ativo (basta executar o comando acima antes de executar qualquer um dos que estão abaixo).
Para executar as migrações, utilize o seguinte comando:
npm run docker:db-migrate-dev
Para seedar o banco de dados, utilize o seguinte comando:
npm run docker:db-seed
Para resetar o banco de dados, utilize o seguinte comando:
npm run docker:db-reset
PS.: Caso você não tenha o NPM instalado no seu ambiente verifique no arquivo package.json
, na seção scripts
qual o comando equivalente ao desejado.
Ex.: Para iniciar o servidor, o comando é npm run docker
.
Na seção scripts
do arquivo package.json
temos o seguinte:
"scripts": {
...
"docker": "docker compose --env-file .env.docker up",
...
},
Portanto, para iniciar o servidor, basta executar o comando:
docker compose --env-file .env.docker up
Também é possível simplesmente acessar o CLI do serviço web
e executar os comandos necessários.
Ambiente de produção
Configurando variáveis de ambiente
Você pode utilizar o arquivo .env
para gerenciar as variáveis de ambiente no ambiente de produção, porém não é recomendado. Verifique em seu serviço de hospedagem como é feita configuração de variáveis de ambiente.
Scripts
Para executar as migrações no banco de dados, utilize o seguinte comando:
npx prisma migrate deploy
Para compilar o projeto, utilize o seguinte comando:
npm run build
PS.: Os arquivos compilados ficam no diretório build/
Para executar o projeto compilado, utilize o seguinte comando:
npm run start
PS.: Caso você esteja utilizando Heroku para realizar o deploy da aplicação (seja para um ambiente de homologação ou de produção), basta configurar as variáveis de ambiente, e pushar o código para o Heroku. Os scripts NPM estão configurados utilizando pre e post hooks de tal forma que os scripts de build e start sejam executados corretamente. Um Procfile
também é disponibilizado no repositório para facilitar o deploy no Heroku.
Estrutura do código fonte
Todo o código de desenvolvimento da API está em src/
.
Em prol de uma melhor organização do código, existe a seguinte estrutura de diretórios:
Routers
routers/
: contém os arquivos de rotas da API.routers/index.ts
: exporta um router que acopla os routers de recursos específicos. Neste arquivo, você deve apenas importar os routers de recursos específicos, sem incluir nenhum middleware.routers/{resource}.router.ts
: define as rotas de um recurso. Ex.:routers/user.router.ts
, abriga as rotas disponíveis para o recurso user. Neste arquivo você apenas deve incluir middlewares caso eles sejam utilizados router level, ou seja, o middleware será aplicado em todas as rotas. O Request Handler não deve ser definido aqui.
Validators
validators/
: contém os arquivos de validação de dados da request.validators/common.validator.ts
: contém validações reaproveitáveis em mais de um modelo. Ex.: Validar que existe um campoid
nos parâmetros da requestvalidators/{model}.validator.ts
: contém as validações de dados de um modelo. Ex.:validators/user.validator.ts
, abriga as validações de dados disponíveis para o modelo user, tal como validação de email, tamanho da senha, entre outros.
Services
services/
: contém os arquivos de serviços (código reaproveitável).services/index.ts
: exporta os serviços disponíveis.services/{service}.service.ts
: Define um serviço como uma classe. Ex.:services/auth.service.ts
, abriga e export a classeAuthService
, responsável por implementar os serviços de autenticação.
Middlewares
middlewares/
: contém os arquivos de middlewares.middlewares/index.ts
: exporta os middlewares disponíveis.middlewares/{name}.middlewares.ts
: implementa um middleware. Exporta uma função que retorna um middleware. Ex.:middlewares/auth.middleware.ts
, export uma função que nao recebe nenhum parâmetro, e retorna uma função (que é o middleware) que verifica se existe um usuário autenticado, e o acopla na request.
Controllers
controllers/
: contém os controllers da aplicação. O controller deve ser responsável por implementar as regras de negócios.controllers/{resource}.controller.ts
: contém o controller de um determinado recurso. O nome de um router e de um controller para esse router devem ser o mesmo. Ex.: Um routerrouters/user.routers.ts
deve ter seu controller com nomecontrollers/user.controller.ts
. O controller de uma rota deve ser exportado como uma constante que armazena um array, e neste array estão incluidos os middlewares necessários para este endpoint, e a função que implementa a regra de negócios. Ex.:controllers/user.controller.ts
, possui um request handler chamadocreate
. Para executar esta função, é necessário que o usuário esteja autenticado, portanto o controller deve incluir o middlewareauthMiddleware
, ficando da seguinte forma...:
const handleCreate = [authMiddleware(), create] as RequestHandler[];
- ...continuando. É necessário o typecasting (
as RequestHandler[]
) para que o TypeScript não reclame sobre o tipo do request handler.
Lib
lib/
: contém arquivos que não se encaixam em nenhum dos diretórios acima. Idealmente, cada arquivo desse diretório deve, idealmente, conter apenas umexport default
.
Para encontrar mais exemplos de como implementar alguma funcionalidade, ou para entender melhor a estrutura e organização do projeto, explore pelo menos um arquivo de cada diretório.
Usuários de VSCode
É recomendada a utilização do VSCode para desenvolver.
As configurações recomendadas para esse projeto estão presentes em .vscode/
. Recomendações de extensões, além de configurações do editor como associação de arquivos, e code actions. Ao abrir o projeto, o VSCode irá detectar automaticamente as recomendações e sugeri-las para você.
Guia de estilo
Foi utilizado como base o guia de estilo airbnb-base
. O mesmo foi adaptado para o projeto, com algumas modificações.
Para fazer linting do código, utilize o seguinte comando:
npm run lint
Para formatar o código, e corrigir erros encontrados pelo linter, utilize o seguinte comando:
npm run lint:fix
Github actions
Para a action Deploy
funcionar, é necessário configurar 3 variáveis de ambiente no github:
HEROKU_API_KEY
: A chave da API do Heroku. Pode ser obtida no Heroku (na seção API Key).
HEROKU_APP_NAME
: O nome da aplicação no Heroku.
HEROKU_EMAIL
: O email do usuário no Heroku.
Para configurar essas variáveis, acesse o repositório no github, e clique em Settings
, e depois, procure na barra de navegação lateral esquerda a opção Secrets
> Actions
. Clique em New repository secret
e preencha os campos Name
e Value
.
A action Deploy
acontece sempre que uma nova release é feita.
Entenda gerenciando releases no Github.
Futuro
- Utilizar algum pattern (UseCases, Services, Repositories, entre outros) para realizar operações de CRUD, ao invés de realizar nos controllers diretamente.
- Implementar validators para validação de dados.
- Testes automatizados.
- Sistema de CI/CD.
- Documentar a API utilizando Swagger UI.