Strutturare un Progetto Express.js: Guida Completa per l'Organizzazione del Codice
Una buona struttura del progetto è fondamentale per mantenere il codice organizzato, scalabile e facile da manutenere, soprattutto man mano che l’applicazione cresce in complessità. Express.js, essendo un framework minimalista, non impone una struttura rigida, il che offre grande flessibilità ma può anche portare a disorganizzazione se non si adottano delle best practices. In questa guida, esploreremo come strutturare un progetto Express.js in modo efficiente.
Struttura Base di un Progetto Express.js
Di seguito è riportata una struttura comune per un progetto Express.js. Questa struttura può variare a seconda delle dimensioni del progetto e delle preferenze dello sviluppatore, ma serve come buon punto di partenza.
my-express-app/
│
├── app.js
├── package.json
├── .env
├── .gitignore
│
├── config/
│ ├── database.js
│ └── config.js
│
├── routes/
│ ├── index.js
│ ├── users.js
│ └── products.js
│
├── controllers/
│ ├── userController.js
│ └── productController.js
│
├── models/
│ ├── user.js
│ └── product.js
│
├── middleware/
│ ├── authMiddleware.js
│ └── errorHandler.js
│
├── views/
│ ├── index.ejs
│ └── error.ejs
│
├── public/
│ ├── css/
│ ├── js/
│ └── images/
│
└── utils/
├── logger.js
└── helpers.js
1. app.js
: Punto di Ingresso dell’Applicazione
Il file app.js
è il punto di ingresso principale della tua applicazione Express. Qui, configuri l’applicazione, definisci i middleware globali, e avvii il server.
const express = require("express");
const app = express();
const routes = require("./routes");
const config = require("./config/config");
// Middleware globali
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// Collegamento delle rotte
app.use("/", routes);
// Gestione degli errori
app.use((req, res, next) => {
res.status(404).render("error", { message: "Pagina non trovata" });
});
app.listen(config.port, () => {
console.log(`Server in ascolto su http://localhost:${config.port}`);
});
2. package.json
: Gestione delle Dipendenze
Il file package.json
definisce le dipendenze del progetto e altre informazioni sul progetto stesso, come il nome, la versione, e gli script di npm.
{
"name": "my-express-app",
"version": "1.0.0",
"description": "Un'applicazione Express.js",
"main": "app.js",
"scripts": {
"start": "node app.js",
"dev": "nodemon app.js"
},
"dependencies": {
"express": "^4.17.1"
},
"devDependencies": {
"nodemon": "^2.0.7"
}
}
3. config/
: Configurazioni dell’Applicazione
La cartella config/
contiene i file di configurazione, come la configurazione del database o altre impostazioni generali.
database.js
: Configurazione della connessione al database.config.js
: Contiene impostazioni generali come la porta su cui il server ascolta e altre variabili di ambiente.
4. routes/
: Definizione delle Rotte
La cartella routes/
contiene tutti i file relativi alle rotte dell’applicazione. Ogni modulo (ad esempio utenti, prodotti) ha un proprio file di rotte.
index.js
: Definisce le rotte principali dell’applicazione, spesso utilizzato per collegare tutte le altre rotte.users.js
: Definisce tutte le rotte relative agli utenti.products.js
: Definisce tutte le rotte relative ai prodotti.
Esempio di un file di rotte (users.js
):
const express = require("express");
const router = express.Router();
const userController = require("../controllers/userController");
router.get("/", userController.getAllUsers);
router.post("/", userController.createUser);
module.exports = router;
5. controllers/
: Logica dell’Applicazione
I controller gestiscono la logica dell’applicazione per ogni rotta. Separare la logica delle rotte dalla logica dell’applicazione migliora la manutenibilità.
userController.js
: Contiene le funzioni per gestire le operazioni relative agli utenti, comegetAllUsers
ocreateUser
.
Esempio di un controller (userController.js
):
const User = require("../models/user");
exports.getAllUsers = (req, res) => {
// Logica per ottenere tutti gli utenti
User.findAll().then((users) => res.json(users));
};
exports.createUser = (req, res) => {
// Logica per creare un nuovo utente
const newUser = new User(req.body);
newUser.save().then((user) => res.status(201).json(user));
};
6. models/
: Modelli di Dati
La cartella models/
contiene i modelli di dati che rappresentano le entità del database. Utilizzando ORM come Sequelize o Mongoose, puoi definire modelli per le tue tabelle o collezioni.
user.js
: Definisce il modello User e le sue proprietà.product.js
: Definisce il modello Product e le sue proprietà.
Esempio di un modello (user.js
) con Mongoose:
const mongoose = require("mongoose");
const userSchema = new mongoose.Schema({
name: String,
email: String,
password: String,
});
module.exports = mongoose.model("User", userSchema);
7. middleware/
: Middleware Personalizzati
La cartella middleware/
contiene middleware personalizzati per gestire operazioni specifiche, come l’autenticazione o la gestione degli errori.
authMiddleware.js
: Verifica che l’utente sia autenticato prima di consentire l’accesso a determinate rotte.errorHandler.js
: Gestisce gli errori generali dell’applicazione.
8. views/
: Template di Visualizzazione
Se stai utilizzando un motore di template come EJS o Pug, la cartella views/
contiene tutti i file di template.
index.ejs
: Template per la homepage.error.ejs
: Template per la pagina di errore.
9. public/
: File Statici
La cartella public/
contiene i file statici dell’applicazione, come CSS, JavaScript client-side, e immagini.
css/
: Fogli di stile CSS.js/
: Script JavaScript per il frontend.images/
: Immagini utilizzate nel sito.
10. utils/
: Utilità e Funzioni Helper
La cartella utils/
contiene funzioni di utilità e helper che possono essere utilizzate in tutto il progetto.
logger.js
: Funzioni per la gestione dei log.helpers.js
: Funzioni helper generali, come la formattazione delle date.
Best Practices per la Strutturazione del Progetto
- Modularità: Mantieni il codice modulare, separando chiaramente la logica delle rotte, la logica dell’applicazione e i modelli di dati.
- Semplicità: Evita di sovrastrutturare l’applicazione, specialmente per progetti più piccoli. Inizia con una struttura semplice e modularla man mano che cresce.
- Manutenibilità: Organizza il codice in modo che sia facile da comprendere e modificare. Ad esempio, se un nuovo sviluppatore si unisce al progetto, dovrebbe essere in grado di navigare facilmente nel codice.
- Separazione delle Preoccupazioni: Mantieni la logica del business separata dalla logica di presentazione e dall’accesso ai dati. Questo aiuta a mantenere il codice pulito e facile da testare.
- Documentazione: Documenta le rotte, i modelli e i controller per facilitare la collaborazione e la manutenzione.
Conclusione
Strutturare correttamente un progetto Express.js è essenziale per mantenere il codice organizzato e scalabile, soprattutto man mano che
l’applicazione cresce in complessità. Seguendo la struttura delineata in questa guida e adottando le best practices, sarai in grado di costruire applicazioni web robuste e manutenibili, pronte per evolversi con le esigenze del progetto.