Dockerizando uma API Express.js com Banco de Dados PostgreSQL para Testes e Produção
Tags: node, docker, api, database
Published: 2024-06-25 20:43:04

Docker é uma ferramenta poderosa que permite criar, implantar e executar aplicativos em contêineres. Neste post, vamos mostrar como dockerizar uma API Express.js com bancos de dados PostgreSQL separados para teste e produção, e como configurar o ambiente para que as alterações locais reflitam no contêiner.


## Pré-requisitos

- Node.js instalado
- Docker instalado
- Docker Compose instalado
- Uma API Node.js existente (ou um novo projeto)
    
##  Criando uma API Express.js

Primeiro, crie um novo projeto Express.js.

```
mkdir node-docker-api
cd node-docker-api
npm init -y
npm install express
npm install -D nodemon 
```

Crie um arquivo `index.js`:

```
const express = require('express');
const app = express();
const port = 3333;

app.use(express.json());

app.get('/', (req, res) => {
  res.send(`Hello, Docker from ${process.env.NODE_ENV} server !`);
});

app.listen(port, () => {
  console.log(`API of ${process.env.NODE_ENV} listening at http://localhost:${port}`);
});
```

## Incremente seu package.json

Crie dois scripts no seu package.json um de `"dev":"NODE_ENV=development nodemon src/index.js"`, para desenvolvimento/testes, e outro de ` "start": "NODE_ENV=production node src/index.js"`, para produção.

```
{
  "name": "node-docker-api",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "NODE_ENV=development nodemon src/index.js",
    "start": "NODE_ENV=production node src/index.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "description": "",
  "dependencies": {
    "express": "^4.19.2"
  },
  "devDependencies": {
    "nodemon": "^3.1.4"
  }
}
```

##  Criando o Dockerfile

Crie um arquivo Dockerfile na raiz do projeto.

```
# Usando uma imagem base oficial do Node.js
FROM node:20-alpine

# Diretório de trabalho dentro do contêiner
WORKDIR /app

# Copiando package.json e package-lock.json
COPY package*.json ./

# Instalando as dependências do projeto dependendo do NODE_ENV
ARG NODE_ENV
RUN if [ "$NODE_ENV" = "production" ]; then npm install --omit=dev; else npm install; fi

# Copiando o restante da aplicação
COPY . .

# Expondo a porta em que a aplicação será executada
EXPOSE 3333

# Definindo a variável de ambiente para desenvolvimento ou produção
ENV NODE_ENV $NODE_ENV

# Comando para rodar a aplicação
CMD ["sh", "-c", "if [ \"$NODE_ENV\" = 'production' ]; then npm start; else npm run dev; fi"]

```

##  Criando um .dockerignore

Crie um arquivo `.dockerignore` para evitar que arquivos desnecessários sejam copiados para a imagem Docker:

```
node_modules
npm-debug.log
.dockerignore
```

##  Criando Arquivos docker-compose

Vamos criar dois arquivos docker-compose: um para desenvolvimento/teste (docker-compose.dev.yaml) e outro para produção (docker-compose.prod.yaml).

`docker-compose.dev.yaml`

Este arquivo conterá a configuração para o ambiente de desenvolvimento e teste.

```
services:
  api:
    build: .
    ports:
      - "3333:3333"
    volumes:
      - .:/app
      - /app/node_modules
    environment:
      - NODE_ENV=development
      - DATABASE_URL=postgresql://postgres:postgres@postgres:5432/devdb
    depends_on:
      - postgres

  postgres:
    image: postgres:latest
    ports:
      - "5432:5432"
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: devdb
    volumes:
      - pgdata:/var/lib/postgresql/data

volumes:
  pgdata:
```

`docker-compose.prod.yaml`

Este arquivo conterá a configuração para o ambiente de produção.

```
services:
  api:
    build: .
    ports:
      - "3333:3333"
    environment:
      - NODE_ENV=production
      - DATABASE_URL=postgresql://postgres:postgres@postgres:5432/proddb
    depends_on:
      - postgres

  postgres:
    image: postgres:latest
    ports:
      - "5432:5432"
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: proddb
    volumes:
      - pgdata:/var/lib/postgresql/data

volumes:
  pgdata:
```

##  Configurando o Ambiente de Desenvolvimento

Para refletir as alterações locais no contêiner, vamos usar o Docker Compose com volumes. O arquivo docker-compose.dev.yaml já está configurado para montar o diretório de trabalho local (.) no contêiner (/app), exceto para node_modules, que será mantido dentro do contêiner para evitar conflitos de dependências.

##  Executando a Aplicação

### Ambiente de Desenvolvimento/Teste

Para o ambiente de desenvolvimento/teste, use o seguinte comando:

```
docker-compose -f docker-compose.dev.yaml up --build
```

### Ambiente de Produção

Para o ambiente de produção, use o seguinte comando:

```
docker-compose -f docker-compose.prod.yaml up --build
```

## Testando a Aplicação

Abra seu navegador e acesse http://localhost:3333. Você deve ver a mensagem "Hello, Docker!".

## Conclusão

Parabéns! Você dockerizou com sucesso sua API Express.js, configurou bancos de dados PostgreSQL diferentes para teste e produção, e configurou o ambiente de desenvolvimento para refletir as alterações locais no contêiner. Dockerizar suas aplicações torna o processo de desenvolvimento, teste e implantação mais consistente e fácil de gerenciar. Continue explorando as funcionalidades do Docker para melhorar ainda mais o seu fluxo de trabalho.

Se você tiver alguma dúvida ou sugestão, sinta-se à vontade para deixar um comentário abaixo!