Implementazione di un dispatcher ed esempio pratico

Vediamo come implementare un dispatcher per le applicazioni Node.JS per creare un webserver evoluto.

Nelle lezioni precedenti abbiamo visto come creare dei semplici server HTTP con Node.js, introducendo i concetti fondamentali del linguaggio. Successivamente abbiamo affrontato alcuni aspetti dell’architettura modulare, utile per utilizzare Node.js in ambito professionale. Armati di questi strumenti possiamo finalmente approfondire l’argomento sia dal punto di vista sintattico che funzionale. Possiamo ad esempio discutere snippet più complesse dal punto di vista della sintassi, senza occuparci di definire l’intera architettura, che resterà comunque modulare. In parole povere tutte le snippet che vedremo in questo articolo andrebbe organizzate in opportuni moduli, seguendo le indicazioni delle lezioni precedenti.

In questa lezione realizzeremo un server HTTP concreto, che debba rispondere a diverse richieste, incaricando di volta in volta il modulo opportuno. In pratica vogliamo realizzare quella che viene detta interfaccia di front-end del server, incaricata di smistare le singole richieste. Un programma di questo tipo può essere chiamato dispatcher, che in italiano potremmo tradurre come “centralino” (traduzione letterale) oppure “smistatore” (traduzione più pratica). In base alla richiesta dell’utente il dispatcher attiverà il modulo opportuno, il quale sarà realizzato usando le funzionalità già viste: questi moduli potrebbe occuparsi, ad esempio, di eseguire una chiamata Ajax, di leggere nel file system, o di comunicare con un altro modulo.

Fortunatamente disponiamo già di tutte le nozioni necessarie per realizzare il dispatcher. La parte più complicata è relativa alle strutture dati da gestire nel paradigma JavaScript. Di primo acchito potrebbe sembrare strano che la parte più difficile sia relativa alle istruzioni Transcriptasi, ma questo è in realtà un punto di forza di Node.js: se conosciamo bene JavaScript (in particolare array e oggetti), il codice che vedremo tra poco non presenterà quasi nulla di nuovo. La novità principale sta nel fatto che useremo le strutture dati familiari agli sviluppatori Web per memorizzare un elenco di listeners, ovvero un elenco di callback che verranno registrate dal dispatcher, in modo da poter poi essere invocate in risposta alle varie richieste.

Per aiutare i meno esperti, in figura 1 abbiamo illustrato l’organizzazione schematica della struttura dati utilizzata. Abbiamo un oggetto con due proprietà: la prima proprietà avrà chiave get, la seconda proprietà avrà chiave post. I valori associati a queste proprietà saranno degli array, avremo perciò un array per ogni proprietà. Per rappresentare la gerarchia strutturale dei dati, leggiamo la figura da sinistra verso destra, come se stessimo “zoomando” la seconda proprietà dell’oggetto originale (la proprietà get).

 

Figura 1 – Struttura dati usata per registrare i listenersdispatcher_01

 

Come si vede dalla figura, gli array associati alle chiavi get e post verranno usati per memorizzare la lista dei vari listeners . Ogni listeners sarà rappresentato da un oggetto JavaScript, a sua volta caratterizzato da due chiavi: la callback che verrà attivata dal dispatcher, associato al suo URL di attivazione.

Array associativi

A pagina precedente abbiamo introdotto la struttura dati che si occupa di memorizzare l’elenco dei listeners. Vediamo adesso come implementare questa struttura dati. In particolare useremo un oggetto di questo tipo:

 

 

Che è proprio l’oggetto principale che memorizza l’elenco di tutti i listeners. Come visto a pagina precedente, l’oggetto dispone di due proprietà (get e post), aventi ciascuna come valore iniziale un array vuoto (le due parentesi quadre). Per comodità assegneremo l’elenco list come attributo di un oggetto specifico, che rappresenta il dispatcher nell’ambito della programmazione Object Oriented. Avremo quindi la “classe JavaScript”: HttpDispatcher:

 

 

il campo leadingName serve per gli eventuali messaggi di debug tramite il comando console.log. Subito dopo troviamo, come attributo di classe, la struttura dati di cui abbiamo parlato finora, seguita dalla funzione addListener, che si occupa di registrare i nuovi listeners all’interno della struttura dati. Essendo questa la parte più complicata del codice, rispolveriamo alcuni dei concetti fondamentali degli array associativi . In particolare ricordiamo che non esiste alcuna differenza sostanziale tra array associativi e oggetti JavaScript: in realtà si parla sempre di oggetti, che possono essere gestiti tramite le API degli array associativi. Ricordiamoci quindi che stiamo usando la sintassi degli array (le parentesi quadre), ma in realtà stiamo accedendo sempre e comunque alle proprietà di un oggetto. Per eventuali approfondimenti rimandiamo a questo articolo.

 

La sintassi degli array associativi permette di scorrere agevolmente l’elenco dei listeners, facendo però attenzione al nome corretto delle proprietà. Supponendo di aver già registrato dei listeners all’interno la classe HttpDispatcher, possiamo analizzare la struttura dati usando una funzione di introspezione, che risulta comoda sia a livello didattico, sia in caso di debug. Aggiungiamo questo metodo nella definizione della classe, subito dopo il corpo del metodo this.addListener.

 

notiamo la sintassi di accesso ai singoli oggetti della struttura dati. Per accedere alla callback del primo listeners del metodo HTTP GET usiamo qualcosa del genere:

mentre sarebbe sbagliato scrivere:

infatti, anche se la proprietà dell’oggetto si chiama “get”, se cercassimo di leggerla come qui sopra di motore JavaScript V8 andrebbe in realtà a cercare la proprietà di nome “key”, che in questo caso non esiste.

Implementazione

Dopo aver chiarito gli aspetti relativi alla sintassi JavaScript, vediamo il codice completo del nostro dispatcher. Per evitare ogni ambiguità riportiamo per intero il codice complessivo della classe HttpDispatcher.

rispetto alla trattazione di pagina precedente abbiamo introdotto due novità: la prima è che il metodo showList adesso viene aggiunto tramite prototype, e non più direttamente nella definizione della classe. Questo approccio è del tutto equivalente a quello di pagina precedente: lo abbiamo scelto solo a scopo didattiche, per da sottolineare che entrambi gli approcci sono ugualmente validi. La seconda novità è rappresentata dall’esportazione del modulo. Invece di spostare una singola funzione (o un elenco di funzioni) come fatto nelle lezioni precedenti, questa volta esportiamo un’istanza dell’oggetto. Ciò significa che quando useremo la funzione require per importare il modulo, di fatto ci verrà ritornato un’istanza della classe HttpDispatcher.

Vediamo finalmente il codice che utilizza il modulo appena creato:

dove chiaramente il file “module-02” conterrà il codice della classe HttpDispatcher. Il codice qui sopra è invece quello del server, che eseguiremo normalmente, lanciandolo da riga di comando (ad esempio node server.js).

Il risultato sarà il seguente: quando lanciamo il server, tramite l’istruzione addListner registriamo la callback che si occupa di gestire le richieste rivolte verso un URL del tipo “/my_page”. La callback è quella scritta qui sopra, che si limita a rispondere con messaggio di testo (Hello World!). Subito dopo invochiamo il metodo di introspezione (cioè showList), per verificare di aver registrato il listener (che non sarà necessario nell’ambiente di produzione).

Il codice complessivo (server più modulo) non ha molte applicazioni pratiche, ma è un ottimo esercizio. Consideriamo di copiare il codice nell’editor che più ci piace e provare ad eseguirlo, per capire come funziona. Eventualmente, se ci sentiamo coraggiosi, troviamo anche a registrare qualche nuovo listeners. Prendere confidenza con questo pattern ci servirà per capire la prossima lezione, nella quale useremo il codice qui discusso per realizzare un dispatcher completo e funzionante.

Facci sapere cosa ne pensi!

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *