08 Node Js e Express
08 Node Js e Express
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
8 [Link]
e Express
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Cos’è
[Link]
[Link] è un “runtime asincrono di JavaScript guidato da eventi"
• runtime JavaScript: [Link] è un programma scritto in C++ che legge ed esegue del codice JavaScript grazie all’engine V8
(lo stesso incluso in Chrome) senza necessità di un browser ed effettua compilazione Just in Time
Possiamo quindi spostarci su un server e costruire web app: JS diventa un linguaggio lato server!
• guidato da eventi: una volta lanciata, l'applicazione rimane in ascolto di specifici eventi e reagisce mediante callback –
[Link] lavora secondo il pattern listener/emitter
• asincrono: [Link] completa i task in maniera asincrona all'interno di un event loop eseguito su un unico thread, grazie a
primitive di I/O che evitano operazioni bloccanti passandole al kernel di sistema e riprendendo l'esecuzione al loro termine
Questo permette a [Link] di gestire migliaia di connessioni concorrenti con un singolo thread senza doverne gestire la
concorrenza
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Cos’è
[Link]
[Link] è un “runtime asincrono di JavaScript guidato da eventi"
Il modello di [Link] è in contrasto con la maggior parte dei modelli di concorrenza odierni, in cui per la gestione delle
connessioni vengono impiegati i thread del sistema operativo
Un'applicazione [Link], invece, viene eseguita in un singolo processo, senza la creazione di un nuovo thread per ogni
richiesta di rete
La strategia di [Link] evita deadlock, in quanto quasi nessuna funzione di [Link] effettua operazioni I/O bloccanti
Fornisce, invece, un insieme di primitive di I/O asincrone (così come le librerie di [Link] sono generalmente scritte
utilizzando paradigmi non bloccanti)
In questo modo, quando è necessario effettuare un'operazione I/O come leggere dalla rete, accedere a un DB o al file
system, anziché bloccare il thread e sprecare CPU, il task viene eseguito in maniera asincrona e [Link] riprende le
operazioni quando ottiene una risposta
Queste caratteristiche permettono a [Link] di gestire migliaia di connessioni concorrenti su un singolo server senza dover
gestire la concorrenza di thread
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Perché
[Link]
Quali sono i vantaggi di [Link]?
• Permette di realizzare un’architettura event-driven che permette di ottimizzare la scalabilità (specie di applicazioni di rete)
grazie al fatto che le operazioni I/O (la maggior parte eseguite dai servizi web) possono essere autonomamente eseguite
all’interno di thread in background e le richieste concorrenti possono essere agevolmente gestite
• Permette di evitare il “context shift” fra linguaggi per lo sviluppo di frontend e backend
• È inserito in un ecosistema ricco con oltre 1,3 milioni di librerie open source, documentate e supportate
• È portabile e multi-piattaforma
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Cos’è
[Link]
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
L’event loop
di [Link]
Una volta eseguito lo script di input, [Link] entra – senza alcuna chiamata bloccante – all'interno di un event loop
L’event loop è ciò che permette a [Link] di effettuare operazioni I/O non bloccanti nonostante JavaScript sia single-thread,
chiedendo quando possibile al kernel di sistema di effettuare queste operazioni
La maggior parte dei kernel moderni è infatti multi-thread, e possono quindi gestire operazioni multiple in background
Quando una di queste operazioni viene completata, il kernel notifica [Link] affinché la callback appropriata venga aggiunta
alla poll queue per essere poi eseguita
Durante la fase di poll, se la coda è non vuota l’event loop
eseguirà le callback in maniera sincrona, fino a svuotarla
Se la coda è vuota, rimane in attesa che venga aggiunta una
nuova callback alla coda
Tuttavia, se sono state schedulate istruzioni del tipo
setImmediate(), esse vengono immediatamente
eseguite mediante la fase di check
Subito dopo, vengono eseguite le callback specificate nei
timer con setTimeout()
(Ricordiamo che i timer specificano la soglia minima dopo
cui una callback deve essere eseguita)
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Installazione e
configurazione
[Link] è platform-independent
È possibile gestire più installazioni di [Link] mediante Node Version Manager (NVM)
nvm list
nvm ls-remote
nvm install 9.3.0
node -v
L'installazione di [Link] rende disponibile anche npm per la gestione di librerie esterne (simile a pip in Python)
Alternativamente, è possibile interpretare il codice JS all'interno del file [Link] con il comando node [Link] o con
node mycode
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Modularità e
Un classico comando
che è possibile
definire in [Link]
on è start che
creazione package
sarà richiamabile con
npm run
start o con npm st
art
Per configurarlo è po
ssibile inserire
nell’elenco degli scrip
t di
[Link] ad esem
Per la gestione dei moduli [Link] utilizza la strategia di CommonJS pio la voce
“start”: “node i
Diversi moduli possono essere organizzati in pacchetti gestiti mediante Node Package Manager [Link]”
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Il modulo
process
Il modulo process (facente parte del core di [Link]) fornisce una serie di metodi e proprietà utili per la gestione del
processo in esecuzione
Esso non necessita di essere importato, in quanto è automaticamente disponibile
[Link]()
È un modo programmatico per terminare l’esecuzione del processo Come impostare una
variabile d’ambiente?
USER_ID=239482 U
SER_KEY=foobar
[Link].VAR_NAME node [Link] quan
do lanciamo
l’applicazione, oppure
Permette di ottenere la variabile d’ambiente VAR_NAME mediante
require(‘dotenv'
).config(); se le
variabili sono imposta
te in un file .env nella
[Link] root del progetto
Permette di ottenere in un array gli argomenti passati allo script
I primi due elementi dell’array sono il path di [Link] e il path dello script
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Il primo
web server
const port = 3000;
const http = require("http");
const httpStatus = require("http-status-codes");
const app = [Link]((req, res) => {
La porta 3000 è
[Link]("Received a request!");
solitamente utilizzata
[Link]([Link], { per i
server di sviluppo
"Content-Type": "text/html"
});
[Link]("<h1>Hello, World!</h1>");
[Link]();
[Link](“Risposta inviata!”);
})
[Link](port, () => {
[Link](`The server has started listening on port ${port}`)
});
http è una libreria standard che introduce un supporto first-class per il networking
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Il primo
web server
Trasformiamo il codice precedente in maniera tale da realizzare un event handler per l’evento request sull’oggetto app
Notiamo che la sintassi per realizzare un event handler in [Link] è [Link](“evento”, callback)
const app = [Link]();
[Link](“request”, (req, res) => {
[Link]([Link], {
Un oggetto di tipo
"Content-Type": "text/html"
EventEmitter disp
}); one
del metodo emit per
[Link]("<h1>Hello, World!</h1>"); generare un evento e
[Link](“Risposta inviata!”); realizzare quindi il pa
ttern
}) listener/emitter
[Link](port, () => {
[Link](`The server has started listening on port ${port}`)
});
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Il primo
web server La classe Buffer perm
di manipolare dati bin
ette
ari
come un array di byte
L’oggetto della richiesta è una istanza di [Link] È utilizzata, ad esemp
io,
Proprietà interessanti di questo oggetto permettono di analizzare il messaggio di richiesta come risposta di molt
i
metodi di lettura dei
file
[Link] [Link] [Link]
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Routing
in [Link]
Con il termine routing ci riferiamo alla determinazione di come
un’applicazione risponde ad una particolare richiesta ad un certo
endpoint (URL) e per un certo metodo
Con il seguente esempio, è possibile richiamare file .html in views/
mediante il loro nome dopo l’hostname
const fs = require(‘fs’);
const getViewUrl = (url) => `views${url}.html`;
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Esercizi
Esercizio 8.1
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Routing
in [Link]
Immaginiamo di realizzare un modulo [Link] (a sinistra) che ci permetta di registrare una serie di route e relative azioni
all’interno di un dizionario e che si occupi poi di gestirle
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Framework
per [Link]
Come abbiamo visto, le API di [Link] risultano essere a basso livello e ciò rende difficoltoso eseguire operazioni più
complesse di routing o di elaborazione di richieste e risposte
A tale proposito, con il tempo sono stati sviluppati framework di più alto livello per [Link] che permettono di velocizzare
e semplificare lo sviluppo di applicazioni web
I web framework permettono, infatti, di superare alcune problematiche comuni di sviluppo come metodi e moduli per
semplificare la gestione di richieste con diversi metodi HTTP, il serving di contenuti statici e dinamici mediante template, la
connessione di database, etc.
Express è abbastanza minimalista, ma gli sviluppatori hanno creato middleware compatibili per la gestione di qualunque
problema di sviluppo (cookie, sessioni, login, parametri di URL, dati da POST, header di sicurezza, …)
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
La prima web app
con Express
const express = require('express');
[Link]() [Link] [Link]()
const app = express();
const port = 3000;
[Link]() [Link] [Link]()
[Link]('/', (req, res) => {
[Link]('Hello World!');
[Link]() [Link] [Link]()
});
Notiamo che il metodo send() sull’oggetto di risposta si comporta in maniera simile al write() del modulo http, i cui
metodi sono ancora supportati da Express
Ricordiamo che write() deve essere però accompagnato da end()
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Routing
in Express
Catena di route
[Link]('/book')
.get((req, res) => {
[Link]('Get a random book’);
})
.post((req, res) => {
[Link]('Add a book’);
})
.put((req, res) => {
[Link]('Update the book’);
});
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Routing
in Express
All’interno dei metodi di routing è possibile specificare percorsi espliciti, o basati su pattern o basati su espressioni regolari, o
basati su parametri
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Uso di
middleware
Dopo la ricezione di una richiesta, Express può eseguire una serie di chiamate a funzioni
middleware intermedie, ad esempio prima che essa venga passata alla logica applicativa
dell’applicazione
Queste funzioni hanno accesso all’oggetto richiesta, all’oggetto risposta e alla funzione
middleware successiva del ciclo di richiesta/risposta (a cui ci si riferisce normalmente con next)
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Uso di
middleware
[Link]()
Ad esempio
[Link](callback)
esegue callback per richieste su qualunque percorso
[Link]('/users', callback)
permette di eseguire callback sul percorso /users e su tutti i
sottopercorsi come /users/tizio e
/users/tizio/photos
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Uso di
middleware [Link](‘/users’, myLogger);
[Link]('/', callback1);
[Link](‘/users/:userId’, callback2)
[Link]()
[Link](3000);
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Uso di
middleware
[Link]('/user/:id', (req, res, next) => {
// se l’ID dell’utente è 0 vai al prossimo route
if ([Link] === '0') next('route')
[Link]('/user/:id', (req, res, next) => {
// altrimenti continua con questo stack
[Link]('ID:', [Link]);
else next()
next();
}, (req, res, next) => {
}, (req, res, next) => {
// send a regular response
[Link]('User Info’);
[Link]('regular')
});
})
// il middleware seguente non verrà mai chiamato
// middleware per una risposta speciale
[Link]('/user/:id', (req, res, next) => {
[Link]('/user/:id', (req, res, next) => {
[Link]([Link]);
[Link]('special')
});
})
eren ze fra ap p. us e( ) e ap p. all()?
D iff
e che
In questo esempio vediamo un middleware substack che Il primo funziona per tutte le rout
ta,
estendono la base route specifica
esegue due callback, ed un middleware che non sarà mai te monta
mentre il secondo semplicemen
utilizzato in quanto il middleware precedente termina il ciclo un middleware per tutti i metod
i su uno
di richiesta/risposta specifico percorso
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Uso di
middleware
[Link]
[Link] permette di creare un router in maniera modulare che fornisca un sistema di routing e di middleware
completo (mini-app)
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Uso di
middleware
In molti casi può essere utile utilizzare middleware built-in come [Link],
[Link] e [Link] oppure middleware esterni come cookie-parser
[Link]([Link]('public', options))
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Uso del
pattern MVC
La strategia principale per utilizzare il pattern MVC all’interno delle nostre web app Express è quella di spostare le funzioni
di callback all’interno di moduli separati che riflettono gli scopi di tali funzioni
Nell’esempio a sinistra, le definizioni delle callback invocate dalle route per la gestione degli account utente svolgono il
ruolo di controller e possono finire in un modulo [Link] all’interno della cartella controllers/
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Uso del
pattern MVC
Per quanto riguarda la realizzazione delle view, Express permette di utilizzare template engine come Pug, Mustache e EJS
Con i template engine è possibile realizzare template di view con variabili popolate dinamicamente e che vengono trasformati
in HTML da inviare ai client
EJS
Il template engine EJS può essere installato con npm install ejs ed il suo utilizzo può essere dichiarato con
[Link]("view engine", "ejs")
All’interno dei simboli <% %> è possibile Il controller si occupa di fare il rendering della view mediante il
scrivere codice JavaScript metodo render sulla risposta, a cui viene passato il nome della view
Mediante <%= %> è possibile stampare il (anche senza estensione) e un oggetto contenente eventuali parametri/
valore di una variabile variabili
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Esercizi
Esercizio 8.2
Realizzare un’applicazione web per un’università utilizzando il pattern MVC e realizzando le viste mediante EJS
In particolare, realizzare una pagina che mostri i diversi corsi offerti dall’ateneo inseriti all’interno di un array, insieme ai
loro metadati
var courses = [
{
name: "Ingegneria Informatica e dell’Automazione",
type: “Corso di Laurea”, Nota bene!
imagePath: … Le viste possono accedere alle
},
{ proprietà dell’oggetto [Link]
name: "Ingegneria Informatica", come se fossero variabili locali
type: “Corso di Laurea Magistrale”, Ad esempio, settando
imagePath: … [Link] = “Prova”
},
{ potremo accedere direttamente alla
name: "Ingegneria Civile e Ambientale", variabile name all’interno della vista
type: “Corso di Laurea”, senza dover passare alcun oggetto
imagePath: …
}
];
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Il database
MongoDB
MongoDB è un database open-source non relazionale che organizza i record come documenti BSON (JSON-like binari)
All’interno di un database, è possibile inserire una o più collezioni, corrispondenti ai modelli dei nostri dati
All’interno di ciascuna collezione è possibile inserire (e ritrovare) tutti i documenti relativi ad uno specifico modello
Ogni documento è un oggetto che consente di memorizzare proprietà mediante il pattern chiave-valore
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Il database
MongoDB
Il database MongoDB può essere installato in locale, oppure è possibile ottenere gratuitamente un’istanza multi-cloud
con MongoDB Atlas
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Il database
MongoDB
MongoDB fornisce il supporto alle operazioni CRUD sui documenti
[Link]({ [Link]()
name: "Ingegneria dell’Automazione”, [Link]({type: “Corso di Laurea”})
type: “Corso di Laurea Magistrale”, [Link]({type: {$in: [“Master”, “Corso di
students: 300 Laurea Magistrale”]}}
}) [Link]({status: “active", $or:
[Link]([…]) [{students: {$lt: 30}}, {other: /^p/}]})
[Link](
[Link]({…}) {students: {$lt: 10}},
[Link]({…}) {$set: {status: “deactivated"}}
)
Per garantire l’unicità dei documenti, MongoDB utilizza una classe ObjectId che permette di rappresentare univocamente
ogni documento nel database
Inoltre MongoDB supporta l’uso di indici, ovvero particolari strutture dati (B-tree) che permettono di memorizzare il valore di
uno o più specifici campi, per poter reperire documenti in maniera più efficiente mediante l’attraversamento dell’albero
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Gestione del DB
con Mongoose
La libreria Mongoose è un object-document mapper che permette di mappare oggetti JavaScript con i documenti di
MongoDB, consentendo di costruire modelli da utilizzare nel pattern MVC in termini di oggetti
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Gestione del DB
con Mongoose
All’interno di uno schema di Mongoose è possibile configurare ciascuna proprietà mediante uno SchemaType, che specifica
il tipo che una proprietà deve avere e quali valori sono validi
const breakfastSchema = [Link]({
• String
eggs: {
type: Number, • Number Ciascun tipo di dato
min: [6, 'Too few eggs'], • Date possiede dei validatori
max: 12 • Buffer propri: approfondisci qui
}, • Boolean
bacon: { • [Link]
type: Number,
required: [true, 'Why no bacon?']
• [Link]
}, • [Link].Decimal128
drink: { • Map
type: String, • [<type>] (array)
enum: {
values: ['Coffee', 'Tea'],
message: '{VALUE} is not supported' I validatori sono regole da poter applicare alle proprietà dei
} modelli per impedire di salvare documenti non validi
required: function() {
return [Link] > 3; La realizzazione di indici in uno schema Mongoose è
} possibile mediante index: true, mentre un indice
}
}); univoco è realizzabile come unique: true
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Gestione del DB
con Mongoose
È possibile aggiungere dei middleware sugli schemi (anche detti pre e post hook) per eseguire delle operazioni prima/dopo
che certe operazioni vengano eseguite
Il middleware andrà inserito subito dopo la definizione dello schema e prima della registrazione del modello
I middleware sono utili per la realizzazione di plugin, ovvero funzionalità preconfezionate per aggiungere funzionalità agli
schemi
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Gestione del DB
con Mongoose
Una volta realizzato un modello, esso può essere utilizzato all’interno dei controller per effettuare operazioni CRUD asincrone
Ad esempio, un controller come il seguente permette di agire all’interno della collezione courses del database in cui stiamo
lavorando (nome lowercase plurale)
[Link] = (req, res, next) => { [Link] = (req, res, next) => {
const newCourse = new Course({ [Link]({
name: 'Ingegneria delle Telecomunicazioni', name: 'Ingegneria delle Telecomunicazioni',
type: 'Corso di Laurea Magistrale', type: 'Corso di Laurea Magistrale',
}); })
[Link]() .then(savedDocument => [Link]('Corso inserito'))
.then(savedDocument => [Link]('Corso inserito')) .catch(error => [Link](error));
.catch(error => [Link](error)); };
};
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Gestione del DB
con Mongoose
Mongoose fornisce un insieme di metodi per effettuare query sui documenti
.find(…)
.findOne(…)
.findById(…)
.findByIdAndUpdate(…) Esplora tutti i metodi per le
.findByIdAndRemove(…) query e le API offerte
.distinct(…)
.delete(…)
.deleteOne(…)
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Associazione one-to-one embedded
con Mongoose })
…
con Mongoose
text: String,
imageUrl: String
})
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Preferiamo una strategia di reference quando vogliamo
con Mongoose certa parola chiave (se i post fossero embedded negli
utenti dovrei prima leggere tutti gli utenti)
Avere bisogno di accedere a un oggetto in sé è una
Come detto precedentemente, MongoDB è un database basato su buona ragione per non renderlo embedded
documenti, pertanto non esistono tabelle e join
Le associazioni fra modelli possono essere fatte in
t i pmaniera
ol o g ie di Associazione one-to-many mediante reference (padre ref. figli)
ed ue
Quale dell
embedded (sottodocumenti) oppure mediantee p r e fe rriferimento
ire? const userSchema = [Link]({
referen c f igli
l'a r ra y d e i …,
ia m o c h e
Se pens o (t a n t o d a posts: [{
r e s ce r e t ropp
possa c re fe r i a mo type: [Link],
One-to-one One-to-many dere")Many-to-many, allor a p
"espl o d re ref: "Post"
n o il p a
h e re f e re nzia }]
figli c
});
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Gestione del DB Associazione many-to-many mediante reference
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Gestione del DB
con Mongoose
Associare un documento a un altro documento è possibile direttamente lavorando come oggetti JavaScript
Ad esempio, è possibile aggiungere un post all’elenco dei post di un utente mediante push sull’array
const testUser;
[Link]({name: “Mario”})
.then(result => testUser = result)
.then(() => [Link]({…}))
.then(createdPost => {
[Link](createdPost);
[Link]();
});
Inoltre, il metodo populate di un modello permette di popolare (ovvero espandere) un documento rispetto a un
particolare modello associato
const testUser;
[Link]({name: “Mario”}).then(result => testUser = result);
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Esercizi
Esercizio 8.3
Realizzare un’applicazione web per un’università che permetta di gestire gli studenti e i corsi di laurea
Realizzare le seguenti funzionalità:
• Visualizzazione di tutti gli studenti
• Inserimento di un nuovo studente mediante form
• Visualizzazione di tutti i corsi di laurea
• Inserimento di un nuovo corso di laurea mediante form
• Iscrizione di uno studente ad un corso di laurea
Nota che è possibile realizzare un controller che faccia il redirect verso una view (ad esempio, dopo aver inserito un
nuovo studente) nella maniera seguente, avendo settato [Link] nel controller precedente
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Gestione del DB
con Mongoose
Finora abbiamo realizzato operazioni CR, ovvero di Create e Read
Come detto, nel linguaggio dei metodi HTTP per le operazioni CRUD (e delle REST API) le operazioni di Update e Delete
corrispondono rispettivamente ai metodi HTTP PUT e DELETE
Ricordiamoci, tuttavia, che HTML supporta solo i metodi GET e POST all’interno dei form
Benché tecnicamente queste operazioni potrebbero essere realizzate con richieste POST, è buona pratica aderire a questo
standard
Una possibile soluzione è quella di inviare richieste POST ad Express ed utilizzare il package method-override per
“sovrascrivere” un metodo in base alla query string dell’URL di richiesta
In questa maniera una POST all’URL /students/:studentID/update?_method=PUT sarà interpretata come una PUT
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Esercizi
Esercizio 8.3 (segue)
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Realizzazione
di API
Nella prima parte di questa introduzione ad Express abbiamo realizzato delle risposte che fornissero agli utenti una vista, ad
es. mediante un approccio a template (server-side rendering)
Andiamo adesso a generalizzare, realizzando delle REST API che siano capaci non solo di fornire viste HTML in risposta alle
richieste, ma che possano essere capaci di far interagire i client (non solo i browser!) con le nostre risorse e rispondere con
qualunque altro formato di dati
Questa strategia è utile, ad esempio, per realizzare Single Page Application (client-side rendering) che richiedono
l’informazione, ricevono l’informazione in formato JSON e modificano di conseguenza la pagina dell’applicazione oppure è
utile per fornire a terze parti l'accesso alla nostra informazione
Inoltre, faremo in modo che ciascun utilizzatore acceda solo alle risorse per le quali è autorizzato ad accedere
Per prima cosa, per mettere ordine, ricordiamoci di organizzare la nostra app mediante namespace di route, spostando le
route di ciascun namespace in un router a sé stante
[Link]([Link]);
Possiamo anche immaginare un controller che supporti diverse tipologie di risposta in base alla richiesta effettuata, ad
esempio in base alla query string potrebbe decidere di fare rendering o meno
A questo punto il client potrà fare una richiesta AJAX appendendo ?format=json al path per ottenere il file JSON da
applicare client-side alla vista
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Realizzazione
di API
Un’altra idea è quella di realizzare un namespace apposito per l’endpoint di API ed utilizzare il relativo middleware
all’interno del router, in maniera tale da raggiungere la stessa API all’indirizzo /api/courses
Il router per le API potrebbe essere implementato nella maniera seguente: Ricordiamo che i controller
vo n o ve ri fic a re c h e l’u te n te sia
d e
const router = require(‘express’).Router(), loggato, ma…
coursesController = require(‘../controllers/courses’);
Chiaramente, dobbiamo supporre di aver creato due middleware appositi per l’invio di risposte JSON
Autenticazione
Autorizzazione
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Sicurezza
delle API
Esempio base
// Protected route
[Link]('/', verifyToken, (req, res) => {
[Link](200).json({ message: 'Protected route accessed' });
});
Chiaramente si tratta di una soluzione artigianale che diventa “pericolosa” se il token viene diffuso in modo incontrollato
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Sicurezza
delle API
Gestione di registrazione e login
Un approccio per gestire la registrazione ed il login è quello di prevedere un campo per la password nello schema degli utenti
Al fine di salvare le password in maniera hash&salt all’interno del database, potremmo utilizzare bcrypt
Ad esempio un pre hook potrebbe gestire l’hashing della password prima del salvataggio nel database e un metodo di
istanza passwordComparison sullo schema degli utenti potrebbe effettuare la comparazione della password inserita
durante il login con la password hashata memorizzata nel database
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Sicurezza
delle API
Autenticazione stateful
Il server crea una sessione per l'utente dopo il login e memorizza l'informazione di sessione lato server
Il server invierà un cookie contenente l'ID di sessione al browser dell'utente, che sarà poi memorizzato e rinviato dall'utente ad
ogni richiesta successiva
Nel cookie non ci saranno dati, ma solo un ID di sessione: i dati saranno memorizzati lato server, grazie ad un apposito store
In Express, possiamo usare la libreria express-session che, letto il cookie, imposta i dati di sessione in [Link]
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Sicurezza
delle API
Autenticazione stateful
[Link]('/login', (req, res) => { function isAuthenticated (req, res, next) {
// verifica username e password, poi... if ([Link]) next()
if (authenticated) { else next('route')
[Link](() => { }
// memorizza le informazioni necessarie
// nella sessione, ad esempio lo username [Link](session({
[Link] = [Link] secret: 'segreto_per_firmare_il_cookie',
[Link](() => { cookie: { maxAge: 60000 }
[Link]('/') }))
})
}) [Link]('/', isAuthenticated, function (req, res) {
}) [Link]('hello, ' + [Link] + '!')
})
[Link]('/logout', (req, res, next) => {
[Link] = null [Link]('/', function (req, res) {
[Link](() => { [Link](loginPage)
[Link](() => { })
[Link]('/')
})
})
})
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Sicurezza
delle API
Autenticazione stateless
Il server non conserva alcuna informazione sulla sessione, pertanto ogni richiesta conterrà tutti i dati necessari per autenticare
l'utente
Se necessario, queste informazioni vengono memorizzate dal client
Si possono utilizzare schemi come la Basic Authentication di HTTP, oppure Access Token come JWT e Bearer token
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Sicurezza
delle API
Autenticazione stateless con Basic Autenthication
[Link]('/',
basicAuth({
users: { username: "password" }, // Elenco (o funzione) di utenti e password ammessi
challenge: true,
unauthorizedResponse:
"Unauthorized access. Please provide valid credentials.",
})
);
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Sicurezza
delle API
Autenticazione stateless con access token JWT
Il JSON Web Token (RFC 7519) è uno standard aperto e usato a livello industriale per trasmettere informazione in maniera
sicura e self-contained fra due parti
Un JWT è rappresentato da tre parti, poi codificate in Base64Url e separate fra loro mediante punti
{ { HMACSHA256( eyJhbGciOiJIUzI1NiIsInR5c
"alg": "HS256", "sub": "1234567890", base64UrlEncode(header) [Link]
"typ": "JWT" "name": "John Doe", + "." + jM0NTY3ODkwIiwibmFtZSI6Ik
} "admin": true base64UrlEncode(payload),
} "mio_segreto" pvaG4gRG9lIiwiYWRtaW4iOnR
) ydWV9.VFnB5SMAgpV0dVLNxkm
ueMxPguP9J7D8KFTBi7ls4mM
Supponiamo, quindi, di voler realizzare un meccanismo di login alle nostre API che produca un access token JWT
Per far ciò, in [Link], possiamo utilizzare la libreria jsonwebtoken
Alle richieste successive, il client invierà nuovamente il token, che sarà utilizzato all’interno di un middleware per il controllo dei
dati di autenticazione
verifyJWT: (req, res, next) => {
let token = ...; // DOBBIAMO RECUPERARE IL TOKEN DALLA RICHIESTA DELL'UTENTE
if (token) {
const decoded = [Link](token, "secret_encoding_passphrase")
if (decoded) {
[Link]([Link]).then(user => {
if (user) {
[Link] = user._id
next(); // Protected route
} else { [Link]('/', verifyJWT, (req, res) => {
[Link]([Link]).json({ [Link](200).json({
error: true, message: 'Protected route accessed' });
message: "No User account found." });
});
}
})
} else { ... }
} else { ... }
}
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Sicurezza Nota b e n e. U n
re
ac
re
ce
vo
ss
c
to
ato/
k e n
delle API
s e
non può es s c a d e da
fi n c hé n on
inva l i da to Puoi approfondire qu
i, qui e qui
solo
Autenticazione stateless con access token JWT
Come detto, il JWT conterrà le informazioni sull’utente e il client dovrà sempre rispedirlo al server che l'ha generato
Ma come può fare il client per memorizzare questo token e rispedirlo al server?
Memorizzazione del token nel localStorage del client e invio come Bearer token nell'header Authorization
Soggetto ad attacchi di tipo XSS (Cross-Site Scripting)
Invio da parte del server Memorizzazione sul client Invio di richieste successive da parte
[Link]({ jwtToken: token }); [Link]('jwtToken', <token>) del client con header
Authorization: Bearer <token>
Memorizzazione del token come cookie
Se non adeguatamente impostato, soggetto ad attacchi di tipo CSRF (Cross-Site Request Forgery)
Invio da parte del server Invio di richieste successive da parte del client con cookie in automatico (su HTTP)
[Link]("jwtToken", signedToken, { Per Fetch API tramite JS può essere necessario impostare
expires: ..., fetch('[Link]
path: '/', ...,
httpOnly: true, credentials: 'include'
secure: true, });
sameSite: 'strict'
})
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Sicurezza La strategia che unisce agli access token anche i refresh token
permette di aumentare il livello di sicurezza
delle API L'access token, che permette l'accesso diretto alle risorse, avrà
Autenticazione con access token e refresh token scadenza breve o brevissima
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
La funzione di login dovrà anzitutto controllare la correttezza di
delle API
const accessToken = [Link]({
_id: user._id,
role: [Link]
}, ACCESS_TOKEN_SECRET, {expiresIn: '10s'})
Autenticazione con access token e refresh token
const refreshToken = // GENERA UNA STRINGA OPACA (O UN JWT)
[Link](ROUTE_NON_PROTETTA, CONTROLLER)
[Link]([Link])
[Link](ROUTE_PROTETTA, CONTROLLER)
[Link](ROUTE_PROTETTA, CONTROLLER)
...
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Dovremo dare la possibilità all'utente di rigenerare un nuovo
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Sicurezza
delle API
OAuth2.0 per l'autorizzazione
Una scelta avanzata per l'autorizzazione delle nostre API è quella di utilizzare il protocollo
OAuth2.0 (Open Authorization), che rappresenta uno standard per l'autorizzazione
delegata delle nostre API
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Sicurezza
delle API
OAuth2.0 per l'autorizzazione
Il cuore del protocollo OAuth è l’Access Token, ovvero una stringa “segreta” che l'applicazione client OAuth utilizza per fare
richieste al server essendo autorizzata ad agire al posto dell'utente
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Sicurezza
delle API
Passport
Passport è un middleware di autenticazione per [Link] che incapsula la sola funzionalità di autenticazione delle richieste,
delegando altri dettagli all'applicazione (separation of concerns)
Passport permette ad un'applicazione di fare uso di un "qualunque" meccanismo di autenticazione, ovvero una qualunque
strategia, ad esempio mediante login locale, sia mediante servizi di terze parti (es. Facebook, Google, …)
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Sicurezza
delle API
Passport
La gestione dell'autenticazione con Passport avviene semplicemente attraverso un middleware che, in caso di successo,
imposterà l'oggetto [Link] all'utente autenticato, stabilirà una sessione e chiamerà il middleware successivo
[Link]('/login/password',
[Link]('local', { failureRedirect: '/login', failureMessage: true }),
function(req, res) {
[Link]('/~' + [Link]);
});
Il meccanismo utilizzato per autenticare la richiesta è implementato da una particolare strategia (nell'esempio in alto, quella
locale che permette di verificare username e password)
Dal momento che Passport implementa numerosissime strategie, il meccanismo di autenticazione definirà come codificare e
come verificare delle credenziali, ad es. un password oppure un'informazione proveniente da un identity provider
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Sicurezza
delle API
Passport
Come detto, è necessario specificare come deve essere trattata la richiesta di autenticazione dell'utente
Ad esempio, la strategia locale legge le credenziali contenute nella richiesta (di default, le proprietà username e password
del corpo della POST) e chiama una funzione (specificata come parametro del costruttore di LocalStrategy) che è
responsabile di determinare l'identità dell'utente
[Link](new LocalStrategy(
function(username, password, done) {
[Link]({ username: username }, function (err, user) {
if (err) { return done(err); }
if (!user) { return done(null, false); }
if () { return done(null, false); }
return done(null, user);
});
}
));
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Sicurezza
delle API
Passport
Passport può fare uso delle sessioni per mantenere lo stato di autenticazione dell'utente
[Link](expressSession({secret: "secret_passcode"}));
La serializzazione permetterà di
[Link]([Link]());
[Link]([Link]()); memorizzare l'oggetto utente all'interno
della sessione
[Link](new LocalStrategy(...); Alle richieste successive, una volta
[Link](function(user, done) {
done(null, { id: [Link], username: [Link] }); autenticato l'utente, l'oggetto viene
}); recuperato dalla sessione e
[Link](function(user, done) { deserializzato, per essere quindi
done(null, user)
impostato come oggetto [Link]
});
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Sicurezza
delle API
Passport
[Link]();
// true o false
[Link];
[Link]();
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Sicurezza
delle API
Passport
L’uso del plugin di Mongoose passport-local-mongoose è conveniente per gestire in maniera semplice la connessione fra
passport-local e Mongoose
[Link](passportLocalMongoose, {
usernameField: “email”
});
A questo punto siamo pronti per gestire la registrazione e il login degli utenti all’interno dei controller della nostra
applicazione
authenticate: [Link]("local", {
failureRedirect: “/users/login”,
failureFlash: “Login non riuscito”,
successRedirect: “/“,
successFlash: “Login riuscito”
})
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026
Sicurezza
delle API
Passport
[Link](expressSession({secret: "secret_passcode"}));
[Link]([Link]());
[Link]([Link]());
[Link](new LocalStrategy([Link]());
[Link]([Link]());
[Link]([Link]());
Antonio Ferrara | Fondamenti del Web (Ingegneria del Software e Fondamenti Web) | A.A. 2025/2026