• Non ci sono risultati.

3 for s in d a t a : 4 if " b i r t h p l a c e " in s : 5 if " l a t i t u d e " not in s [" b i r t h p l a c e "] or " l o n g i t u d e " not in s [" b i r t h p l a c e "]: 6 if " m u n i c i p a l i t y " in s [" b i r t h p l a c e "]: 7 a d d r e s s S t r i n g = s [" b i r t h p l a c e " ] [ " m u n i c i p a l i t y "] 8 try : 9 l o c a t i o n = g e o l o c a t o r . g e o c o d e ( a d d r e s s S t r i n g ) 10 s [" b i r t h p l a c e " ] [ " l a t i t u d e "] = l o c a t i o n . l a t i t u d e 11 s [" b i r t h p l a c e " ] [ " l o n g i t u d e "] = l o c a t i o n . l o n g i t u d e 12 e x c e p t : 13 p a s s 14 15 # qui o p e r a z i o n i a n a l o g h e per r e s i d e n z a e d o m i c i l i o

Il database `e stato popolato anche con dati relativi ai corsi di laurea offerti dall’Universit`a di Bologna[72] e dati geometrici sui confini perimetrali dei quartieri di Bologna[73], attraverso metodi similari a quelli utilizzati per gli studenti.

3.2

Struttura dell’applicazione

L’applicazione ha un’architettura client-server: tutto ci`o che riguarda l’interfaccia del sito `e contenuto nella cartella client , mentre la connessione e le interazioni col database sono gestite all’interno della cartella server .

Sia nella cartella principale del progetto che nelle due sottocartelle `e sta- to eseguito il comando npm init , che per ciascuna di loro ha creato il file package.json . Esso elenca le dipendenze del progetto, ovvero le librerie usate e le rispettive versioni minime richieste. Durante lo sviluppo, sono state man mano installate nuove librerie col comando npm install <nome package> , che aggiorna il file package.json e le colloca nella cartella node modules .

Il package.json nella cartella principale include tra le dipendenze unica- mente la libreria concurrently , che si occupa di avviare sia il lato client che

il lato server concorrentemente all’esecuzione di npm start (o di npm run start-build per buildare il frontend con i tool messi a disposizione da Create React App).

I package.json nelle sottocartelle contengono informazioni sulle librerie utilizzate nel relativo contesto (client o server).

3.2.1

Server

Il lato server `e concentrato nel file index.js nella cartella server , dove `e stato utilizzato un oggetto Koa denominato app per contenere una serie di middleware eseguiti uno dietro l’altro all’effettuazione di una richiesta. Ini- zialmente vengono avviati middleware forniti da diversi moduli Koa: cors , utilizzato per rendere possibile un fetch dal client con origine (dominio, pro- tocollo, porta) diversa, e bodyParser , per collocare il corpo dello stream di richiesta in ctx.request.body . A seguire, viene utilizzato un middleware chiamato errorhandler che ha il compito di restituire un risultato d’errore nel caso le operazioni dei middleware successivi non vadano a buon fine. Il corpo di questo middleware, cos`ı come quelli degli altri middleware originali, sono collocati nella cartella middlewares .

1 a s y n c ( ctx , n e x t ) = > { 2 try { 3 a w a i t n e x t () ; 4 } c a t c h ( err ) { 5 ctx . b o d y = { s u c c e s s : false , e r r o r : err } 6 ctx . s t a t u s = 4 0 4 ; 7 } 8 }

Il middleware successivo, db , si occupa di creare una nuova connessio- ne al database e renderla accessibile tramite ctx.db , per poi chiuderla al termine delle operazioni successive.

1 a s y n c ( ctx , n e x t ) = > { 2 try {

3.2 Struttura dell’applicazione 49 3 ctx . db = a w a i t m o n g o o s e . c r e a t e C o n n e c t i o n ( D B _ R O U T E , { u s e N e w U r l P a r s e r : true , u s e F i n d A n d M o d i f y : f a l s e }) ; 4 a w a i t n e x t () ; 5 } f i n a l l y { 6 if ( ctx . db ) { 7 a w a i t ctx . db . c l o s e () ; 8 } 9 } 10 };

Vengono poi configurate due route relative rispettivamente all’inizializ- zazione dei dati nel database ( /api/init ) e al loro recupero ( /api/get ), ed importate da middlewares/routes . La prima definisce un modello per ciascuna collection nel database (Student, Neighborhood, DegreesSeat; stu- denti, quartieri, corsi di laurea) utilizzando i relativi Schema nella cartella schemas , e li utilizza per resettare i dati attualmente memorizzati e caricare quelli contenuti nei relativi file JSON collocati nella cartella collections . 1 // x = s t u d e n t / n e i g h b o r h o o d / d e g r e e s S e a t 2 3 a s y n c ( ctx , n e x t ) = > { 4 var x s M o d e l = a w a i t ctx . db . m o d e l (" X " , r e q u i r e ( " . . / . . / s c h e m a s / x ") ) 5 var x s C o l l e c t i o n = r e q u i r e ( " . . / . . / c o l l e c t i o n s / xs . j s o n ") ; 6 7 a w a i t x s M o d e l . c o l l e c t i o n . d e l e t e M a n y ( { } ) ; 8 9 for ( c o n s t d o c u m e n t of x s C o l l e c t i o n ) { 10 a w a i t ( new x s M o d e l ( d o c u m e n t ) ) . s a v e () ; 11 }; 12 13 ctx . b o d y = { s u c c e s s : t r u e }; 14 ctx . s t a t u s = 2 0 0 ; 15 16 a w a i t n e x t () ; 17 }

L’altra route si occupa semplicemente di recuperare i dati nel database e restituirli nel corpo dell’oggetto risposta.

1 a s y n c ( ctx , n e x t ) = > { 2 var s t u d e n t s M o d e l = a w a i t ctx . db . m o d e l (" S t u d e n t " , r e q u i r e ( " . . / . . / s c h e m a s / s t u d e n t ") ) 3 var n e i g h b o r h o o d s M o d e l = a w a i t ctx . db . m o d e l (" N e i g h b o r h o o d " , r e q u i r e ( ’ . . / . . / s c h e m a s / n e i g h b o r h o o d ") ) 4 var d e g r e e s S e a t s M o d e l = a w a i t ctx . db . m o d e l (" D e g r e e s S e a t " , r e q u i r e ( " . . / . . / s c h e m a s / d e g r e e s S e a t ") ) 5 var s t u d e n t s = a w a i t s t u d e n t s M o d e l . f i n d () . e x e c () ; 6 var n e i g h b o r h o o d s = a w a i t n e i g h b o r h o o d s M o d e l . f i n d () . e x e c () ; 7 var d e g r e e s S e a t s = a w a i t d e g r e e s S e a t s M o d e l . f i n d () . e x e c () ; 8 9 ctx . b o d y = { 10 s u c c e s s : true , 11 s t u d e n t s : s t u d e n t s , 12 n e i g h b o r h o o d s : n e i g h b o r h o o d s , 13 d e g r e e s S e a t s : d e g r e e s S e a t s 14 }; 15 ctx . s t a t u s = 2 0 0 ; 16 }

Tutte funzioni di connessione e interazione col database, come find() e deleteMany() , fanno parte della libreria Mongoose.

L’ultima riga del file server/index.js si occupa di mettere in ascolto il server alla porta 3001 mediante il metodo app.listen() .

3.2.2

Client

Il lato client `e stato costruito con l’ambiente Create React App, una libre- ria ideata appositamente per fornire una serie di tool selezionati e gi`a configu- rati per creare applicazioni con React. All’avvio, viene renderizzato un com- ponente Router contenente una Route per il componente App principale al percorso / all’interno dell’elemento con id root del file index.html .

3.2 Struttura dell’applicazione 51 1 R e a c t D O M . r e n d e r ( < Router > 2 < R o u t e e x a c t p a t h = " / " c o m p o n e n t = { ( ) = > < App / >} / > 3 </ Router > , d o c u m e n t . g e t E l e m e n t B y I d (" r o o t ") ) ; 4 s e r v i c e W o r k e r () ;

Il componente App renderizza tre sottocomponenti: Navbar , una barra di navigazione che fa uso di componenti Link per reindirizzare la pagina alle sue sottosezioni con ancoraggi; MapPanel , ovvero la sottointerfaccia di vi- sualizzazione dei dati degli studenti in una mappa geografica; ChartPanel , che racchiude la rappresentazioni dei dati sotto forma di grafici. Essi so- no racchiusi in React.Fragment , un componente utilizzato per racchiudere molteplici elementi senza generare nodi aggiuntivi nel DOM, come ad esempio dei div .

Una volta che App `e stato montato (quando gli elementi HTML relativi

sono stati aggiunti al DOM), viene effettuato un fetch al server per ricavare tutti i dati presenti nel database relativi agli studenti, ai quartieri e ai corsi di laurea, per poi passarli ai componenti figli MapPanel e ChartPanel utilizzando delle funzioni a loro disposizione richiamabili attraverso delle refs, propriet`a di React create e poi assegnate ai componenti figli. Oltre a questi dati, vengono passate le props prese in ingresso da App relative alle opzioni selezionate inizialmente dai ReactResponsiveSelect .

La gestione di props mancanti e di tipo errato avviene attraverso, ri-

spettivamente, le propriet`a statiche dei componenti React defaultProps e

propTypes .

I componenti dell’applicazione sono contenuti nella sottocartella components . Sono presenti anche la cartella styles , che racchiude i file .module.css e

.module.scss con gli stili CSS utilizzati da alcuni componenti, e la cartella utilities , contenente funzioni di utilit`a richiamate pi`u volte.

Oltre agli stili CSS menzionati precendentemente, il progetto fa uso del framework Bootstrap, installato come le altre librerie con npm .

Documenti correlati