🚀 Nuova versione beta disponibile! Feedback o problemi? Contattaci

Strutturare un Progetto Express.js: Guida Completa per l'Organizzazione del Codice

Codegrind TeamAug 28 2024

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, come getAllUsers o createUser.

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

  1. Modularità: Mantieni il codice modulare, separando chiaramente la logica delle rotte, la logica dell’applicazione e i modelli di dati.
  2. Semplicità: Evita di sovrastrutturare l’applicazione, specialmente per progetti più piccoli. Inizia con una struttura semplice e modularla man mano che cresce.
  3. 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.
  4. 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.
  5. 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.