Melhores Práticas para Estruturar Projetos Express.js

Express.js é um framework minimalista e flexível para Node.js, amplamente utilizado para criar aplicações web e APIs. Estruturar adequadamente um projeto Express.js é essencial para facilitar a manutenção, melhorar a escalabilidade e garantir a eficiência do desenvolvimento. Este artigo apresenta as melhores práticas para estruturar projetos Express.js, abordando desde a organização de arquivos e pastas até o uso de middlewares e boas práticas de codificação.

Pré-requisitos

Para seguir este guia, você precisará de:

  1. Conhecimento básico de JavaScript e Node.js
  2. Experiência com Express.js
  3. Node.js e npm instalados em seu ambiente de desenvolvimento

Setup Steps

Passo 1: Configuração do Ambiente

Primeiro, instale o Node.js e o npm (Node Package Manager) no seu sistema. Acesse o site oficial do Node.js para baixar e instalar a versão recomendada.

Passo 2: Inicializar o Projeto

Crie uma nova pasta para o seu projeto e inicialize um novo projeto Node.js com o npm:

mkdir meu-projeto-express
cd meu-projeto-express
npm init -y

Passo 3: Instalar Dependências

Instale as dependências principais, incluindo o Express.js:

npm install express body-parser mongoose dotenv

Instale também as dependências de desenvolvimento para facilitar o trabalho durante o desenvolvimento:

npm install --save-dev nodemon

Estrutura de Pastas

A organização das pastas é crucial para manter o código limpo e modular. Abaixo está um exemplo de estrutura de pastas recomendada para um projeto Express.js:

project-root/
│
├── src/
│   ├── config/
│   │   └── db.js
│   ├── controllers/
│   │   └── userController.js
│   ├── models/
│   │   └── userModel.js
│   ├── routes/
│   │   └── userRoutes.js
│   ├── middlewares/
│   │   └── authMiddleware.js
│   ├── utils/
│   │   └── helper.js
│   ├── app.js
│   └── server.js
│
├── test/
│   └── userController.test.js
│
├── node_modules/
│
├── .env
├── .gitignore
├── package.json
├── package-lock.json
└── README.md

Organização do Código

app.js

O arquivo app.js é onde você configura e inicia o Express.js, configura os middlewares e define as rotas principais.

const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const userRoutes = require('./routes/userRoutes');

// Middlewares
app.use(bodyParser.json());

// Rotas
app.use('/api/users', userRoutes);

module.exports = app;

server.js

O arquivo server.js é responsável por iniciar o servidor.

const app = require('./app');
const dotenv = require('dotenv');

dotenv.config();

const PORT = process.env.PORT || 3000;

app.listen(PORT, () => {
    console.log(`Server is running on port ${PORT}`);
});

Configuração do Banco de Dados

Coloque todas as configurações do banco de dados em uma pasta separada (config/). Isso facilita a modificação e a reutilização do código.

// config/db.js
const mongoose = require('mongoose');
const dotenv = require('dotenv');

dotenv.config();

const connectDB = async () => {
    try {
        await mongoose.connect(process.env.MONGO_URI, {
            useNewUrlParser: true,
            useUnifiedTopology: true,
            useCreateIndex: true,
        });
        console.log('MongoDB connected');
    } catch (error) {
        console.error('MongoDB connection error:', error);
        process.exit(1);
    }
};

module.exports = connectDB;

Controladores

Os controladores devem conter a lógica das rotas e interagir com os modelos. Mantenha-os simples e focados em suas responsabilidades específicas.

// controllers/userController.js
const User = require('../models/userModel');

const getUsers = async (req, res) => {
    try {
        const users = await User.find();
        res.status(200).json(users);
    } catch (error) {
        res.status(500).json({ message: error.message });
    }
};

const createUser = async (req, res) => {
    const user = new User(req.body);
    try {
        await user.save();
        res.status(201).json(user);
    } catch (error) {
        res.status(400).json({ message: error.message });
    }
};

module.exports = { getUsers, createUser };

Modelos

Os modelos devem representar a estrutura dos dados e interagir com o banco de dados.

// models/userModel.js
const mongoose = require('mongoose');

const userSchema = new mongoose.Schema({
    name: { type: String, required: true },
    email: { type: String, required: true, unique: true },
    password: { type: String, required: true },
}, {
    timestamps: true
});

const User = mongoose.model('User', userSchema);

module.exports = User;

Rotas

As rotas definem os endpoints e chamam os controladores apropriados.

// routes/userRoutes.js
const express = require('express');
const router = express.Router();
const { getUsers, createUser } = require('../controllers/userController');

router.get('/', getUsers);
router.post('/', createUser);

module.exports = router;

Middlewares

Os middlewares são utilizados para interceptar e manipular requisições antes que elas alcancem os controladores.

// middlewares/authMiddleware.js
const jwt = require('jsonwebtoken');

const authMiddleware = (req, res, next) => {
    const token = req.header('Authorization');
    if (!token) {
        return res.status(401).json({ message: 'No token, authorization denied' });
    }

    try {
        const decoded = jwt.verify(token, process.env.JWT_SECRET);
        req.user = decoded.user;
        next();
    } catch (error) {
        res.status(401).json({ message: 'Token is not valid' });
    }
};

module.exports = authMiddleware;

Testes

Mantenha os testes em uma pasta separada (test/) e use frameworks de teste como Mocha, Chai ou Jest para garantir a qualidade do código.

// test/userController.test.js
const request = require('supertest');
const app = require('../src/app');

describe('GET /api/users', () => {
    it('should return all users', async () => {
        const res = await request(app).get('/api/users');
        expect(res.statusCode).toBe(200);
        expect(res.body).toBeInstanceOf(Array);
    });
});

Conclusão

Seguir estas melhores práticas para estruturar projetos Express.js ajudará a manter o código organizado, modular e fácil de manter. Estruturar o código adequadamente é fundamental para o sucesso a longo prazo de qualquer projeto de desenvolvimento. Adote essas práticas desde o início do seu projeto para garantir uma base sólida e escalável.


Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *