"Sono stato bocciato a parecchi esami. Un mio amico invece, li ha passati tutti a pieni voti. Ora è ingegnere e lavora in Microsoft. Io sono il proprietario."  - Bill Gates  •  "Se riesco a fare qualcosa in 10 minuti, è perché ho passato anni a studiarlo."  - Bill Gates  •  "Il vostro lavoro riempirà gran parte della vostra vita, e l'unico modo per essere veramente soddisfatti è fare ciò che ritenete sia un grande lavoro."  - Steve Jobs  •  "Siate affamati. Siate folli."  - Steve Jobs  •  

cinque 

ZERO

{Node.js} API – Interrogare il webserver: I middleware

home / javascript /

Lucio Paolo Asciolla

Senior Full Stack Developer

Cosa sono i Middleware?

I middleware sono funzioni che possono essere eseguite durante una richiesta al webserver.
Sono funzioni eseguibili quindi tra la richiesta e la risposta.

request >middleware >response

Si tratta sostanzialmente di un terzo parametro, che è una funzione, da poter passare all'interno della richiesta.

app.get('/', middleWareFunction, function(request,response){
response.send("Hello world!");
});

Middleware

La funzione, middleware, che possiamo dichiarare esternamente, e che sarà successivamente inserite come parametro all'interno della richiesta, potrà utilizzare alcune proprietà dell'oggetto "request".

methodrestituisce il metodo della richiesta
urlrestituisce l'url della richiesta

Per farlo dobbiamo passare alla funzione tre parametri: request, response e next.

var middleWareFunction = function(request,response,next){
var {method, url} = request;
console.log(method, url);
};

Seppur questi parametri esternamente alla richiesta, nel contesto globale, non sono accessibili, lo diventeranno quando inseriremo il middleware all'interno della nostra richiesta.

var middleWareFunction = function(request,response,next){
var {method, url} = request;
console.log(method, url);
next();
};

app.get('/', middleWareFunction, function(request,response){
response.send("Hello world!");
});

Se proviamo a collegarci alla root principale "localhost:3000" quello che otterremo è il messaggio "Hello World!" nel browser, mentre nella CLI di node.js quanto segue:

GET è il metodo utilizzato, mentre "/" rappresenta la root principale.

next

"next" rappresenta un parametro, che utilizzeremo come funzione;
Dobbiamo immaginare le funzioni all'interno di una richiesta come due funzioni di callback che devono essere eseguite una dopo l'altra.
Le funzioni all'interno di una richiesta devono necessariamente restituire una risposta.

var middleWareFunction = function(request,response,next){
var {method, url} = request;
console.log(method, url);
next();
//oppure
//response.send("Qualunque cosa");
};

Una richiesta può contenere un unica risposta, quindi, se inglobassimo un "response.send()" all'interno del middleware, la risposta all'interno della funzione contenuta all'interno della richiesta sarebbe ignorata.
Motivo per il quale è necessario l'utilizzo di "next()".

Data e ora della richiesta e della risposta

Se necessitiamo di conoscere l'orario esatto dell'invio della richiesta potremo procedere in questo modo:

var middleWareFunction = function(request,response,next){
    var {method, url} = request;
    var timeOfRequest = new Date();
    console.log(method, url);
    console.log('Data e ora della richiesta: ' + timeOfRequest);
    next();
    };

Essendo il middleware tra la richiesta e la risposta, sarà sufficiente creare una variabile "timeOfRequest" in cui contenere al suo interno una nuova data corrente sfruttando "new Date()".
Lo stesso potremo fare nella seconda callback, ultima funzione, contenuta in "app.get()" per conoscere il momento della risposta.
Trattandosi in genere di risposte molto rapide dovremo lavorare sui millisecondi.

middleware come modulo

Trattandosi di una semplice funzione nessuno ci vieta di separarlo dal corpo del nostro index.js creando un modulo apposito.
Potremo quindi creare un file "middleware.js" preoccupandoci di renderlo esportabile

Ed importarlo successivamente nel nostro index.js

auto-middleware su tutte le richeste

Possiamo utilizzare un middleware su tutte le richieste di un'app express senza dover indicare ad ogni richiesta il middleware da utilizzare.
Per farlo utilizziamo il metodo app.use().

const express = require('express');
cosnt app = express();
const middleWare = require('./middleware');

app.use(middleWare);

app.get('/', function(request,response){
response.send("Homepage");
});
app.get('/articoli', function(request,response){
response.send("Articoli");
});
app.get('/prodotti', function(request,response){
response.send("Prodotti");
});

app.listen(3000);

auto-middleware su percorsi specifici

E' inoltre possibile limitare a determinati endpoint l'utilizzo dei middleware;
Potremo attuare questa restrizione includendo un nuovo parametro al metodo app.use():

...
app.use('/prodotti', middleware);
..

Così facendo limitiamo l'utilizzo dei middleware solo ai percorsi che iniziano con "localhost/3000/prodotti/"

localhost/3000/prodotti/
localhost/3000/prodotti/prodotto1
localhost/3000/prodotti/prodotto2
...

auto-middleware multipli

Possiamo includere nelle nostre richieste più middleware sempre mediante l'utilizzo di "app.use()"

const primoMiddleWare = require('./primoMiddleWare');
const secondoMiddleWare = require('./secondoMiddleWare');

app.use([primoMiddleWare, secondoMiddleWare]);
//oppure
app.use('/prodotti', [primoMiddleWare, secondoMiddleWare]);
...

Per farlo dobbiamo passare al metodo ".use()" un array di middleware.
E' importante che "app.use()" sia inserito prima di tutte le richieste "app.get()" o quanto meno prima degli endpoint che ne saranno interessati.

Allo stesso modo è possibile specificare più middleware all'interno della stessa richiesta

...
app.get('/chisiamo', [primoMiddleWare, secondoMiddleWare], function(request,response){...});

middleware di terze-parti

Finora abbiamo imparato a gestire middleware da noi creati che essi siano dichiarati esternamente ma nel contesto globale, richiamati nella richiesta stessa, implementati in moduli custom esterni al file principale, multipli ecc.
E' bene sapere che i middleware possono essere sviluppati da terze parti e contenere particolari funzionalità.
Si tratta di middleware, si pensi alla stessa autorizzazione di accesso, non realizzati da noi, importati in Node.js, cosi come facciamo con i moduli.
Questi middleware una volta importati saranno utilizzabili all'interno delle nostre richieste.

Utilizzo dei middleware per autorizzazione all'accesso a dati earee private

I middleware, trovandosi tra la richiesta e la risposta, sono utilizzati spesso per gestire l'accesso a dati, risorse, pagine private.

Quello che segue, seppur estremamente semplificato ed insicuro (non prevedendo nessuna particolare protezione) è un esempio di middleware che gestisce la richiesta di un utente di accedere ad una determinata pagina e si pone tra quest'ultima e la risposta effettuando un controllo mediante l'istruzione "if"

const auth = function(request, response, next){
var {username} = request.query;
if(username == "SuperUser"){
next();
}else{
response.send("Accesso negato");
}

Stiamo recuperando dalla quey-string mediante l'oggetto "request.query" il valore del paramentro "username"; se è uguale a "SuperUser" gli indichiamo di proseguire con "next()" altrimenti restituiamo una risposta, "response" alla richiesta di "accesso negato".
Ricordiamo che una richiesta può avere un unica risposta e che nel middleware è presente una "response" le successive saranno ignorate.

app.get('/areaprivata', auth, function(request,response){
response.send("Accesso Effettuato;
});