{"id":11822,"date":"2016-05-30T17:42:44","date_gmt":"2016-05-30T15:42:44","guid":{"rendered":"http:\/\/www.devapp.it\/wordpress\/?p=11822"},"modified":"2016-06-07T14:49:37","modified_gmt":"2016-06-07T12:49:37","slug":"node-js-api-rest-con-database-relazionale","status":"publish","type":"post","link":"https:\/\/www.devapp.it\/wordpress\/node-js-api-rest-con-database-relazionale\/","title":{"rendered":"Node.js: API REST con database relazionale"},"content":{"rendered":"<p>In alcuni articoli precedenti, pubblicati sulle nostre pagine, abbiamo proposto un&#8217;<a href=\"http:\/\/www.devapp.it\/wordpress\/introduzione-a-node-js\/\">introduzione a\u00a0Node.js<\/a>, ambiente Javascript per l&#8217;esecuzione di applicazioni stand-alone da eseguire senza il supporto di un browser. Abbiamo visto come <a href=\"http:\/\/www.devapp.it\/wordpress\/creare-api-rest-con-node-js-ed-express-js\/\">integrare Express.js in Node.js<\/a> fornisca un server HTTP gi\u00e0 pronto per configurare le nostre API REST. Oggi proseguiremo il discorso approfondendo alcuni aspetti di Express.js ancora non affrontati e forniremo\u00a0il backend di un database relazionale.<\/p>\n<h2>Node.js e Sqlite<\/h2>\n<p>Per questo esempio, abbiamo scelto di dotare il nostro servizio di un database <a href=\"https:\/\/www.sqlite.org\/\" target=\"_blank\">SQLite<\/a>,\u00a0ma buona parte dei principi che enunceremo varranno per un p\u00f2 tutti i DBMS relazionali esistenti. Sqlite &#8211; per chi non lo conoscesse &#8211; \u00e8 uno dei motori di database pi\u00f9 diffusi al mondo. Ci\u00f2 che lo distingue \u00e8 la sua leggerezza ed estrema portabilit\u00e0. Infatti Sqlite non \u00e8 un servizio da mandare in esecuzione ma una libreria che va collegata alla propria applicazione &#8211; lo si pu\u00f2 fare praticamente con ogni tecnologia &#8211; ed \u00e8 in grado di mantenere un database relazionale in un unico file.<br \/>\nPer il nostro esempio, abbiamo preparato un semplice database &#8211; di nome <em>dbesempio.db<\/em> &#8211; composto da un&#8217;unica tabella, la cui struttura \u00e8 mostrata nel seguente script SQL:<\/p>\n<pre class=\"lang:mysql decode:true \">CREATE TABLE `persone` (\r\n\t`id`\tINTEGER PRIMARY KEY AUTOINCREMENT,\r\n\t`nome`\tTEXT,\r\n\t`cognome`\tTEXT,\r\n\t`eta`\tINTEGER,\r\n\t`citta`\tTEXT\r\n);<\/pre>\n<p>Ogni suo record rappresenta una persona che abbiamo\u00a0registrato, definita da nome , cognome, et\u00e0 e citt\u00e0, il tutto univocamente identificato da una\u00a0chiave primaria intera auto-incrementante.<\/p>\n<p>In Node.js dovremo, per prima cosa, integrare\u00a0il modulo per Sqlite, ma grazie a <em>npm<\/em> non sar\u00e0 affatto complicato.<br \/>\nImpartiremo da riga di comando:<\/p>\n<pre class=\"lang:sh decode:true \">npm install sqlite3 --save<\/pre>\n<p>Al termine dello scaricamento, avremo tale modulo a disposizione della nostra installazione Node.js e per attivarlo saranno sufficienti le seguenti righe nel nostro codice Javascript:<\/p>\n<pre class=\"lang:js decode:true \">var sqlite3 = require('sqlite3').verbose();\r\nvar db = new sqlite3.Database('dbesempio.db');<\/pre>\n<p>A questo punto,\u00a0l&#8217;oggetto db ricever\u00e0 comandi da tradurre in operazioni sul database dbesempio.db.<\/p>\n<p>Il modulo per Sqlite offre un insieme di metodi per svolgere tutte le operazioni principali. Nell&#8217;esempio, eseguiremo query ed inserimento di dati. Il funzionamento della libreria \u00e8 <em>asincrono<\/em>: il metodo che utilizzeremo per i comandi richieder\u00e0 il codice SQL ed una funzione di callback che tratter\u00e0 i risultati ottenuti. Come si pu\u00f2 presumere, a seconda del comando inoltrato, la funzione di callback avr\u00e0 funzionalit\u00e0 e scopi diversi.<\/p>\n<h2>L&#8217;esempio<\/h2>\n<p>Supponiamo che il nostro server sia messo in esecuzione all&#8217;indirizzo <em>http:\/\/192.168.100.1<\/em> alla porta TCP 4157.<\/p>\n<p>Nelle nostre API predisporremo tre possibili richieste:<\/p>\n<ul>\n<li>una <strong>GET<\/strong> sull&#8217;URL <strong>http:\/\/192.168.100.1\/db\/tutti<\/strong> che restituir\u00e0 un array di oggetti JSON ognuno contenente i dati di una persona;<\/li>\n<li>una <strong>GET<\/strong> sull&#8217;URL <strong>http:\/\/192.168.100.1\/db\/<em>:citta<\/em><\/strong> dove al posto del parametro <em>:citta<\/em> passeremo direttamente il nome della citt\u00e0 da usare\u00a0per filtrare i risultati: otterremo un array JSON anche in questo caso, ma contenente solo i dati di persone residenti nella citt\u00e0 indicata. Ad esempio:\n<pre class=\"lang:sh decode:true \">http:\/\/192.168.100.1\/db\/Roma<\/pre>\n<p>restituit\u00e0 solo i record che vedranno nel campo <em>citta<\/em> la parola &#8220;Roma&#8221;;<\/li>\n<li>una <strong>POST<\/strong> all&#8217;indirizzo <strong>http:\/\/192.168.100.1\/db\/nuova<\/strong> che ricever\u00e0 nel corpo della richiesta un oggetto JSON con i nuovi dati. Il risultato sar\u00e0, in caso di successo, l&#8217;id del record appena creato ed il codice di stato HTTP sar\u00e0 impostato a 202, viceversa, qualora si verificassero errori,\u00a0il codice sar\u00e0 500 ed il corpo della risposta conterr\u00e0 l&#8217;oggetto di errore restituito\u00a0da Express.<\/li>\n<\/ul>\n<p>Questo il codice:<\/p>\n<pre class=\"lang:js decode:true\">var express = require('express');\r\nvar sqlite3 = require('sqlite3').verbose();\r\nvar db = new sqlite3.Database('dbesempio.db');\r\nvar bodyParser=require('body-parser');\r\n\r\nvar app=express();\r\napp.use(bodyParser.json());\r\n\r\napp.get('\/db\/tutti', function (req, res) {\r\n\tdb.all(\"SELECT * FROM persone\", \r\n\t\tfunction(e,r)\r\n\t\t{\r\n\t\t\tres.json(r);\r\n\t\t});\r\n});\r\n\r\napp.get('\/db\/:citta', function(req,res)\r\n{\r\n\tdb.all(\"SELECT * FROM persone WHERE citta=?\",req.params.citta,\r\n\t\t\tfunction(e,r)\r\n\t\t\t{\r\n\t\t\t  res.json(r);\r\n             });\r\n});\r\n\r\napp.post('\/db\/nuova', function(req,res)\r\n{ \r\ndb.run(\"INERT INTO persone (nome,cognome,citta,eta) VALUES (?,?,?,?)\", [req.body.nome,req.body.cognome,req.body.citta,req.body.eta], \r\n   function(e,r)\r\n    {\r\n       if (e==null)\r\n\t  res.status(202).json({\"id\":this.lastID});\r\n\r\n       else\r\n\t  res.status(500).end();\r\n    });\r\n\t\t\r\n});\r\n\r\napp.listen(4157, function () {\r\n  console.log('Server in esecuzione sulla porta 4157...');\r\n});<\/pre>\n<p>Per eseguirlo, dovremo includere nella cartella che lo contiene il database dbesempio.db ed attivare lo script che nel nostro caso si chiama app.js:<\/p>\n<pre class=\"lang:sh decode:true \">node app.js<\/pre>\n<p>Come vediamo nelle ultime righe del listato, il servizio verr\u00e0 avviato sulla porta 4157 ed in output verr\u00e0 prodotto il messaggio:<\/p>\n<pre class=\"lang:sh decode:true \">Server in esecuzione sulla porta 4157...<\/pre>\n<p>Per svolgere le prove sar\u00e0 necessario un client HTTP. Se ne pu\u00f2 usare uno di proprio gradimento\u00a0o creare un programma che interagisca col servizio: a parere nostro, a scopo di test, uno strumento molto valido pu\u00f2 riultare\u00a0<a href=\"http:\/\/www.devapp.it\/wordpress\/postman-sviluppa-le-tue-api-piu-velocemente.html\" target=\"_blank\">Postman<\/a>, di cui abbiamo parlato in un precedente articolo.<\/p>\n<h2>Analizziamo il codice<\/h2>\n<p>Vediamo ora nel dettaglio come abbiamo realizzato il nostro servizio. Dopo le inizializzazioni delle prime righe, istanziamo\u00a0un body parser:<\/p>\n<pre class=\"lang:js decode:true \">var bodyParser=require('body-parser');\r\n...\r\n...\r\napp.use(bodyParser.json());<\/pre>\n<p>che si far\u00e0 carico di interpretare in automatico i corpi delle richieste compilati in formato JSON.<\/p>\n<p>Come fatto nelle lezioni precedenti, configureremo le funzionalit\u00e0 delle API tramite gli appositi metodi <em>get<\/em>\u00a0e\u00a0<em>post<\/em>\u00a0(eventualmente ci servissero, esistono anche\u00a0<em>delete<\/em> e <em>put<\/em>)\u00a0contenuti nell&#8217;oggetto app e, al loro interno, invocheremo le operazioni relative al\u00a0database.<\/p>\n<p>Il metodo <em>all<\/em> del modulo Sqlite viene usato per recuperare tutti i risultati di una query. Nel metodo di callback, verranno restituiti due oggetti contenenti, rispettivamente, un eventuale errore o il set di risultati ottenuti:<\/p>\n<pre class=\"lang:js decode:true \">db.all(\"SELECT * FROM persone\", \r\n\t\tfunction(e,r)\r\n\t\t{\r\n\t\t\tres.json(r);\r\n\t\t});<\/pre>\n<p>Essendo i risultati restituiti come array di oggetti Javascript, potremo direttamente inviarli al client con il metodo <em>json<\/em>.<\/p>\n<p>La seconda funzionalit\u00e0 GET\u00a0deve eseguire una query in base al parametro &#8220;:citta&#8221; inviato all&#8217;interno dell&#8217;URL:<\/p>\n<pre class=\"lang:js decode:true \">db.all(\"SELECT * FROM persone WHERE citta=?\",req.params.citta,\r\n\t\t\tfunction(e,r)\r\n\t\t\t{\r\n\t\t\t  res.json(r);\r\n             });<\/pre>\n<p>Notare in questo caso come la query sia stata costituita in forma parametrica: in pratica il codice SQL contiene solo la parte immutabile mentre i valori della clausola WHERE sono sostituiti da punti interrogativi (?). Questi ultimi\u00a0funzioneranno a mo&#8217; di\u00a0segnaposto e, in fase di esecuzione, verranno rimpiazzati da\u00a0altrettanti valori passati prima della funzione di callback. Questa modalit\u00e0 evita noiose concatenazioni di SQL preimpostato e valori passati a tempo di esecuzione.<\/p>\n<p>Anche nel metodo <em>post<\/em> il comando SQL \u00e8 espresso in forma parametrica ed i valori attuali saranno passati sotto forma di array essendo pi\u00f9 di uno.<\/p>\n<pre class=\"lang:js decode:true \">db.run(\"INSERT INTO persone (nome,cognome,citta,eta) VALUES (?,?,?,?)\", [req.body.nome,req.body.cognome,req.body.citta,req.body.eta], \r\n   function(e,r)\r\n    {\r\n       if (e==null)\r\n\t  res.status(202).json({\"id\":this.lastID});\r\n\r\n       else\r\n\t  res.status(500).end();\r\n    });\r\n<\/pre>\n<p>Nella funzione di callback il parametro &#8220;e&#8221; sar\u00e0 <em>null<\/em> a meno che non si siano verificati errori mentre l&#8217;id dell&#8217;ultimo inserimento sar\u00e0 reso disponibile nella propriet\u00e0 <em>lastID<\/em> disponibile tramite il riferimento <em>this<\/em>.<\/p>\n<p>Il metodo <em>status<\/em> applicato alla risposta permette di indicare\u00a0il codice di stato HTTP.<\/p>\n<h2>Conclusioni<\/h2>\n<p>Con questo articolo abbiamo fatto un ulteriore passo avanti nel nostro percorso: abbiamo introdotto un database relazionale che potr\u00e0 cos\u00ec essere gestito da remoto, ad esempio, inviando comandi da una nostra applicazione Android. In aggiunta a quanto visto si potranno usare ulteriori metodi del modulo Sqlite come <em>each<\/em> per eseguire la funzione di callback su ogni record restituito da una query oppure <em>get<\/em> che elabora solo il primo record dei risultati (pensiamo ad una SELECT COUNT che deve solo fornire una riga con il numero di record contenuti nella tabella). Ci sono anche <em>prepared statement<\/em> e altre funzioni illustrate nella <a href=\"https:\/\/github.com\/mapbox\/node-sqlite3\/wiki\/API\" target=\"_blank\">documentazione ufficiale<\/a>.<\/p>\n<p>Quanto fatto sinora sar\u00e0 proseguito nelle prossime lezioni dove vedremo come arricchire ulteriormente le nostre API REST con Node.js: continuate quindi a seguirci e suggerite idee attraverso\u00a0i commenti!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In alcuni articoli precedenti, pubblicati sulle nostre pagine, abbiamo proposto un&#8217;introduzione a\u00a0Node.js, ambiente Javascript per l&#8217;esecuzione di&#8230;<\/p>\n","protected":false},"author":561,"featured_media":11863,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[1698,1696,1697,1649,1537],"class_list":["post-11822","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-tutorial-pratici","tag-backend-developers","tag-creare-api-rest","tag-database-sqlite","tag-javascript-developers","tag-node-js"],"acf":[],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/11822","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/users\/561"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/comments?post=11822"}],"version-history":[{"count":14,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/11822\/revisions"}],"predecessor-version":[{"id":12075,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/11822\/revisions\/12075"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/media\/11863"}],"wp:attachment":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/media?parent=11822"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/categories?post=11822"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/tags?post=11822"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}