In questo post implementeremo le funzionalità di eliminazione e inserimento di un libro nella nostra biblioteca.
Se andate al solito indirizzo https://whispering-peak-1284.herokuapp.com/ ed entrate con l'utente admin ivan con password saracino, troverete le funzionalità già implementate.
Quando visualizzerete la lista dei libri, noterete una immagine cliccabile di un cestino a fianco di ogni libro che implementa l'operazione di eliminazione del libro.
Provate a testare tali funzionalità e ad implementarle seguendo l'architettura proposta.
Nel prossimo post troverete la soluzione e l'intera implementazione :)
Buon Lavoro.
Alla prox.
Ivan
Ho deciso di creare questo blog per condividere la mia passione verso un linguaggio, Javascript, spesso bistrattato e considerato di serie B, solo perché non lo si conosce a fondo.
Partirò dalle basi con l'obiettivo di approfondire la piattaforma node.js.
Visualizzazione post con etichetta module revealed pattern. Mostra tutti i post
Visualizzazione post con etichetta module revealed pattern. Mostra tutti i post
venerdì, gennaio 16, 2015
mercoledì, gennaio 14, 2015
Biblioteca: visualizziamo la lista dei libri
Ora che l'architettura della nostra applicazione è ben delineata, risulta molto semplice aggiungere le funzionalità rimanenti decise in fase di analisi
Con l'approccio modulare visto fino ad ora, basta aggiungere due ulteriori moduli per
Il menu dinamico in funzione del profilo dell'utente che ha effettuato o meno l'accesso, lo modifichiamo in questo modo
Nel prossimo post, vedremo come implementare la ricerca, ma ormai dovrebbe essere chiaro, spero, come sia strutturato il codice.
Su https://whispering-peak-1284.herokuapp.com/ potete testare le funzionalità appena implementate.
Come al solito, ho aggiornato su github il progetto installato su heroku, in modo che possiate avere sempre tutto il codice a disposizione, in questo post è spiegato come utilizzare github.
Dopo aver fatto il pull del progetto, ricordatevi di eseguire, se non lo avete mai fatto, npm install nella cartella di progetto;
Se volete eseguire il programma in locale digitate node app.js e puntate il browser all'indirizzo http://localhost:5000.
Alla prox
Ivan
Con l'approccio modulare visto fino ad ora, basta aggiungere due ulteriori moduli per
- la gestione delle rotte (richieste) relative alle gestione dei libri (lista, ricerca,rimozione ...) in routes/libri.js
- implementazione logica di business relativa alla gestione dei libri in servizi/serviziLibri.js
if (!session.utente)
ul(class='nav nav-pils')
li(role='presentation')
a(href='/utente/login') Login
li(role='presentation')
a(href='/utente/registrazione') Registrati!
else
ul(class='nav nav-pils')
li(role='presentation')
a(href='/utente/logout') Logout
li(role='presentation')
a(href='/libri') Lista Libri
li(role='presentation')
a(href='/libri/cerca') Cerca Libro
if (session.utente.profilo === 'admin')
li(role='presentation')
a(href='/libri/nuovo') Nuovo Libro
Nel caso di utente che accede con il profilo semplice, attiviamo nel menu le rotte (link di richiesta)- /libri per visualizzare la lista dei libri
- /libri/cerca per visualizzare un form di ricerca libro
- /libri/nuovo per visualizzare un form di inserimento di un nuovo libro
var libri = require('./routes/libri');
...
app.use('/libri', libri);
Il modulo libri fornisce, per ora, la gestione della rotta radice /
var express = require('express');
var router = express.Router();
var serviziLibri = require('../servizi/serviziLibri');
router.route('/')
.get(function(request,response) {
var libri = serviziLibri.listaLibri();
response.render('listalibri', {libri : libri});
});
module.exports = router;
e quindi la lista dei libri sarà visualizzata a seguito della richiesta all'indirizzo /libri utilizzando la nuova vista presente in /views/listalibri.jade
extends ./layout.jade
block titolo
title Lista Libri
block testata
h1.text-info Lista Libri!
block contenuti-principali
if (libri)
table(class='table table-striped table-bordered')
thead
tr
th Codice
th Titolo
th Autore
each libro in libri
tr
td #{libro.codiceisbn}
td #{libro.titolo}
td #{libro.autore}
Il modulo serviziLibri sarà così implementato, sempre utilizzando la tecnica delle funzioni definite ed eseguite immediatamente
module.exports = (function(){
var libri = [
{
titolo : 'Il signore degli anelli',
codiceisbn: 'DRF00223Z',
autore: 'John Ronald Reuel Tolkjen'
},
{
titolo : 'Guerra e pace',
codiceisbn: 'FTGR44E3',
autore: 'Lev Tolstoj'
},
{
titolo : 'Javascript the good parts',
codiceisbn: 'ZZ3423DR665',
autore: 'Douglas Crockford'
}
];
var listaLibri = function() {
return libri;
};
return {
listaLibri : listaLibri
};
})();
Come si può osservare, continuiamo ancora ad utilizzare una base dati in memoria, tra qualche post sostituiremo il codice presente il questo modulo con quello relativo alla interazione con una base dati.Nel prossimo post, vedremo come implementare la ricerca, ma ormai dovrebbe essere chiaro, spero, come sia strutturato il codice.
Su https://whispering-peak-1284.herokuapp.com/ potete testare le funzionalità appena implementate.
Come al solito, ho aggiornato su github il progetto installato su heroku, in modo che possiate avere sempre tutto il codice a disposizione, in questo post è spiegato come utilizzare github.
Dopo aver fatto il pull del progetto, ricordatevi di eseguire, se non lo avete mai fatto, npm install nella cartella di progetto;
Se volete eseguire il programma in locale digitate node app.js e puntate il browser all'indirizzo http://localhost:5000.
Alla prox
Ivan
lunedì, gennaio 12, 2015
Biblioteca: altro modulo per gestire la logica di business
Oggi implementeremo le funzionalità core di login e registrazione.
Non introdurremo ancora l'interazione con un server di dati per non appesantire l'esposizione, utilizzeremo una struttura dati in memoria per memorizzare le utenze, ma struttureremo il codice in maniera tale da non dover modificare la parte di gestione delle varie richieste presenti nel modulo delle rotte degli utenti: come? Ma utilizzando un altro bel raviolone :).
Prima di mettere il naso nel codice, navigate l'applicazione aggiornata su heroku per capire dove vogliamo andare a parare: https://whispering-peak-1284.herokuapp.com.
Provate a fare il login con username ivan e password saracino, che ha un profilo admin, notate come il menu presenti funzionalità (da implementare) di amministrazione.
Fate il logout per pulire la sessione e entrate nella pagina di registrazione, inserendo una vostra utenza; verrete rediretti alla pagina di login con un opportuno messaggio per effettuare l'autenticazione con le credenziali appena create: rifate il login e notate come cambia il menu e i messaggi di benvenuto presenti nell'header.
Ad ogni riavvio della applicazione, ovviamente tutte le utenze create non ci saranno più, rimarrà valido solo l'utente admin ivan saracino.
Per capire come abbiamo strutturato il codice, date un'occhiata al seguente diagramma di oggetti
Vi ricordo che moduli nel contesto javascript non sono altro che oggetti che espongono particolari proprietà che possono essere anche funzioni.
Il diagramma in alto non dice altro che il modulo app utilizza il modulo delle rotte utenti che a sua volta utilizza il modulo serviziUtenze: grazie a questa separazione di responsabilità tra moduli diversi sarà facile tenere sotto controllo la complessità del nostro progetto.
Il modulo utenti ha la responsabilità di definire le funzioni da eseguire per gestire le varie funzionalità legate agli utenti quali il login e la registrazione.
Prendiamo ad esempio la richiesta /utente/login e osserviamo come nel caso di una richiesta get venga semplicemente renderizzata la pagina login.jade, mentre nel caso di una richiesta di tipo post venga utilizzato il modulo serviziUtenze per effettuare la vera e propria autenticazione.
Per estrarre i parametri dalla richiesta post, basta usare un codice del tipo request.body.nomeparametro.
Nel modulo serviziUtenze risiede la logica di business vera e propria, in questo caso abbiamo creato un modulo che espone due metodi login e registra che utilizzano un array di oggetti in memoria come base dati delle utenze inizializzato con l'utente admin ivan saracino.
Per la generazione del menu dinamico, osserviamo il file menu.jade incluso nel layout
Non abbiamo implementato una validazione dei parametri passati al server, nel prossimo post vedremo come affrontare questo argomento tramite l'utilizzo di un middleware opportuno.
Come al solito, ho aggiornato su github il progetto installato su heroku, in modo che possiate avere sempre tutto il codice a disposizione, in questo post è spiegato come utilizzare github.
Dopo aver fatto il pull del progetto, ricordatevi di eseguire npm install nella cartella di progetto per installare la dipendenza aggiuntiva per il modulo body-parser : se volete eseguire il programma in locale digitate node app.js e puntate il browser all'indirizzo http://localhost:5000.
Alla prox
Ivan
Non introdurremo ancora l'interazione con un server di dati per non appesantire l'esposizione, utilizzeremo una struttura dati in memoria per memorizzare le utenze, ma struttureremo il codice in maniera tale da non dover modificare la parte di gestione delle varie richieste presenti nel modulo delle rotte degli utenti: come? Ma utilizzando un altro bel raviolone :).
Prima di mettere il naso nel codice, navigate l'applicazione aggiornata su heroku per capire dove vogliamo andare a parare: https://whispering-peak-1284.herokuapp.com.
Provate a fare il login con username ivan e password saracino, che ha un profilo admin, notate come il menu presenti funzionalità (da implementare) di amministrazione.
Fate il logout per pulire la sessione e entrate nella pagina di registrazione, inserendo una vostra utenza; verrete rediretti alla pagina di login con un opportuno messaggio per effettuare l'autenticazione con le credenziali appena create: rifate il login e notate come cambia il menu e i messaggi di benvenuto presenti nell'header.
Ad ogni riavvio della applicazione, ovviamente tutte le utenze create non ci saranno più, rimarrà valido solo l'utente admin ivan saracino.
Per capire come abbiamo strutturato il codice, date un'occhiata al seguente diagramma di oggetti
Vi ricordo che moduli nel contesto javascript non sono altro che oggetti che espongono particolari proprietà che possono essere anche funzioni.
Il diagramma in alto non dice altro che il modulo app utilizza il modulo delle rotte utenti che a sua volta utilizza il modulo serviziUtenze: grazie a questa separazione di responsabilità tra moduli diversi sarà facile tenere sotto controllo la complessità del nostro progetto.
Il modulo app ha la responsabilità di configurare l'intera applicazione, tramite, ad esempio, l'utilizzo di moduli particolari di express per la gestione delle sessioni o il parsing del corpo delle richieste http: per poter effettuare il post dei form, dovremo includere nel codice del modulo app le seguenti istruzioni
var bodyParser = require('body-parser');
...
app.use(bodyParser.urlencoded({ extended: true }));
In questo modo sarà possibile estrarre facilmente i parametri mandati in post al server al submit del form.Il modulo utenti ha la responsabilità di definire le funzioni da eseguire per gestire le varie funzionalità legate agli utenti quali il login e la registrazione.
var express = require('express');
var router = express.Router();
var serviziBiblioteca = require('../servizi/serviziUtenze');
router.route('/login')
.get(function(request,response) {
response.render('login');
})
.post(function(request,response){
var utente = serviziBiblioteca.login(
request.body.username,
request.body.password
);
if (utente) {
request.session.utente = utente;
response.render('home');
}
else {
response.render(
'login',
{ loginFallito : 'Utente non abilitato'}
);
}
});
router.route('/registrazione')
.get(function(request,response) {
response.render('registrazione');
})
.post(function(request,response) {
var utente = {};
utente.username = request.body.username;
utente.password = request.body.password;
utente.email = request.body.email;
utente.profilo = 'semplice';
serviziBiblioteca.registra(utente);
response.render('login', {
registrazioneOk: 'Ora puoi effettuare il login!'});
});
router.route('/logout')
.get(function(request,response) {
request.session.destroy(function() {
response.redirect('/');
});
});
module.exports = router;
Notate dal codice come sia possibile gestire una richiesta sia in get che in post.Prendiamo ad esempio la richiesta /utente/login e osserviamo come nel caso di una richiesta get venga semplicemente renderizzata la pagina login.jade, mentre nel caso di una richiesta di tipo post venga utilizzato il modulo serviziUtenze per effettuare la vera e propria autenticazione.
Per estrarre i parametri dalla richiesta post, basta usare un codice del tipo request.body.nomeparametro.
Nel modulo serviziUtenze risiede la logica di business vera e propria, in questo caso abbiamo creato un modulo che espone due metodi login e registra che utilizzano un array di oggetti in memoria come base dati delle utenze inizializzato con l'utente admin ivan saracino.
module.exports = (function(){
var utentiRegistrati = [
{
username : 'ivan',
password: 'saracino',
email: 'ivan.saracino@gmail.com',
profilo: 'admin'
}
];
var login = function(username,password) {
var utentiLoggati = utentiRegistrati.filter(function(utente) {
return utente.username === username &&
utente.password === password;
});
return utentiLoggati[0];
};
var registra = function(utente) {
utentiRegistrati.push(utente);
console.log(utentiRegistrati);
};
return {
login : login,
registra : registra
};
})();
Per organizzare meglio i file, abbiamo previsto la presenza di una cartella servizi in cui memorizzare
i file dei moduli della logica di business: non è difficile prevedere la presenza di un ulteriore modulo per la gestione dei libri quando andremo ad implementare tali funzionalità.Per la generazione del menu dinamico, osserviamo il file menu.jade incluso nel layout
if (!session.utente)
ul(class='nav nav-pils')
li(role='presentation')
a(href='/utente/login') Login
li(role='presentation')
a(href='/utente/registrazione') Registrati!
else
ul(class='nav nav-pils')
li(role='presentation')
a(href='/utente/logout') Logout
if (session.utente.profilo === 'semplice')
li(role='presentation')
a(href='#') link semplice 1
li(role='presentation')
a(href='#') link semplice 2
else
li(role='presentation')
a(href='#') link admin 1
li(role="presentation")
a(href='#') link admin 2
Se esiste un utente in sessione, ne verrà controllato il profilo per generare opportunamente i link corretti.Non abbiamo implementato una validazione dei parametri passati al server, nel prossimo post vedremo come affrontare questo argomento tramite l'utilizzo di un middleware opportuno.
Come al solito, ho aggiornato su github il progetto installato su heroku, in modo che possiate avere sempre tutto il codice a disposizione, in questo post è spiegato come utilizzare github.
Dopo aver fatto il pull del progetto, ricordatevi di eseguire npm install nella cartella di progetto per installare la dipendenza aggiuntiva per il modulo body-parser : se volete eseguire il programma in locale digitate node app.js e puntate il browser all'indirizzo http://localhost:5000.
Alla prox
Ivan
giovedì, dicembre 04, 2014
Esercitazioni su node.js: esercizio 7
Testo dell'esercizio
Giusto per ribadire il concetto di stream che genera eventi asincroni da gestire, scrivere un programma, come il precedente, per effettuare una richiesta HTTP di tipo GET all'indirizzo http://cspnet.it, questa volta però, visualizzare tutti i dati della risposta solo quando la richiesta è terminata.
Come ulteriore vincolo, l'unica variabile globale, (a livello di intero programma, esterna a qualsiasi funzione) deve essere solo la variabile var http = require('http');
Suggerimenti
Ricordate che l'evento data viene generato piu' volte, al termine della visualizzazione della risposta (che sarà ovviamente la pagina html home del sito di csp), provate infatti a stampare il numero di volte che è stato emesso l'evento data.
Per il vincolo richiesto, non scordate le IIF
Buon lavoro!
Una possibile soluzione
L'oggetto response vedetelo come un flusso di dati che viene alimentato dal server e letto dal client quando i dati sono disponibili.
Per motivi di efficienza, i dati non sono mandati in un unico blocco, l'evento 'data' dello stream response viene emesso più volte ed ogni volta viene eseguita la funzione di callback che accoda i dati ricevuti nella variabile totalData e incrementa il contatore numeroChunk.
Quando non ci sono più dati, lo stream emette l'evento end, che ci permette di definire una funzione di callback che stampa a video i dati finali.
Ho aggiornato su github il progetto, effettuate un git pull per aggiornare i sorgenti che avete in locale, come mostrato in questo post
Come al solito, per dubbi e/o domande: commentate!
Alla prox.
Ivan
Giusto per ribadire il concetto di stream che genera eventi asincroni da gestire, scrivere un programma, come il precedente, per effettuare una richiesta HTTP di tipo GET all'indirizzo http://cspnet.it, questa volta però, visualizzare tutti i dati della risposta solo quando la richiesta è terminata.
Come ulteriore vincolo, l'unica variabile globale, (a livello di intero programma, esterna a qualsiasi funzione) deve essere solo la variabile var http = require('http');
Suggerimenti
Ricordate che l'evento data viene generato piu' volte, al termine della visualizzazione della risposta (che sarà ovviamente la pagina html home del sito di csp), provate infatti a stampare il numero di volte che è stato emesso l'evento data.
Per il vincolo richiesto, non scordate le IIF
Buon lavoro!
Una possibile soluzione
var http = require('http'),
i = 0;
(function() {
var totalData = "",
numeroChunk = 0;
http.get('http://cspnet.it', function (response) {
response.setEncoding('utf8');
response.on('data', function(data) {
totalData += data;
numeroChunk++;
});
response.on('error', console.error);
response.on('end', function() {
console.log("FINITO: " +
totalData +
" NUMERO CHUNK " +
numeroChunk);
});
});
})();
Il prossimo post verterà sul potente concetto di stream in node.js.L'oggetto response vedetelo come un flusso di dati che viene alimentato dal server e letto dal client quando i dati sono disponibili.
Per motivi di efficienza, i dati non sono mandati in un unico blocco, l'evento 'data' dello stream response viene emesso più volte ed ogni volta viene eseguita la funzione di callback che accoda i dati ricevuti nella variabile totalData e incrementa il contatore numeroChunk.
Quando non ci sono più dati, lo stream emette l'evento end, che ci permette di definire una funzione di callback che stampa a video i dati finali.
Ho aggiornato su github il progetto, effettuate un git pull per aggiornare i sorgenti che avete in locale, come mostrato in questo post
Come al solito, per dubbi e/o domande: commentate!
Alla prox.
Ivan
Iscriviti a:
Post (Atom)

