A partir da conexão com o banco de dados já estabelecida, podemos avançar para a criação de uma estrutura mais organizada para nossa aplicação utilizando o padrão MVC (Models, Views, Controllers) – embora, em APIs, geralmente não precisemos de Views. Neste tutorial, vamos criar Endpoints, Controllers e Models usando o Express para estruturar nossa aplicação de forma modular e escalável.
Uma organização comum para um projeto Node.js com Express pode ser a seguinte:
.
├── config/
│ └── db.js
├── controllers/
│ └── usuarioController.js
├── models/
│ └── usuarioModel.js
├── routes/
│ └── usuarioRoutes.js
├── .env
├── .gitignore
└── app.js
Cada pasta possui sua responsabilidade:
No Model, encapsulamos as operações de acesso ao banco de dados. Por exemplo, crie o arquivo models/usuarioModel.js:
const db = require('../config/db');
const UsuarioModel = {
async getAllUsuarios() {
const result = await db.query('SELECT * FROM usuarios');
return result.rows;
},
async getUsuarioById(id) {
const result = await db.query('SELECT * FROM usuarios WHERE id = $1', [id]);
return result.rows[0];
},
async createUsuario({ nome, email }) {
const result = await db.query(
'INSERT INTO usuarios (nome, email) VALUES ($1, $2) RETURNING *',
[nome, email]
);
return result.rows[0];
}
};
module.exports = UsuarioModel;
Aqui, estamos definindo métodos assíncronos que executam consultas usando o pool configurado em db.js.
O Controller atua como intermediário entre as requisições HTTP e as operações do Model. Crie o arquivo controllers/usuarioController.js:
const UsuarioModel = require('../models/usuarioModel');
const UsuarioController = {
async listarUsuarios(req, res) {
try {
const usuarios = await UsuarioModel.getAllUsuarios();
return res.status(200).json(usuarios);
} catch (error) {
console.error(error);
return res.status(500).json({ error: 'Erro ao listar usuários' });
}
},
async obterUsuario(req, res) {
try {
const { id } = req.params;
const usuario = await UsuarioModel.getUsuarioById(id);
if (!usuario) {
return res.status(404).json({ error: 'Usuário não encontrado' });
}
return res.status(200).json(usuario);
} catch (error) {
console.error(error);
return res.status(500).json({ error: 'Erro ao obter usuário' });
}
},
async criarUsuario(req, res) {
try {
const novoUsuario = await UsuarioModel.createUsuario(req.body);
return res.status(201).json(novoUsuario);
} catch (error) {
console.error(error);
return res.status(500).json({ error: 'Erro ao criar usuário' });
}
}
};
module.exports = UsuarioController;
Cada método do controller trata da lógica necessária para processar a requisição, interage com o model e envia a resposta adequada.