Tempo di lettura: 13 minuti
In questa mini guida andremo a realizzare una REST API con Nodejs ed Express nello specifico realizzeremo un’applicazione per la gestione di libri.
Con il termine REST API (REPRESENTATION STATE TRANSFER APPLICATION PROGRAMMING INTERFACE) ci si riferisce a quei metodi con il quale un client può richiedere informazioni dal server seguendo un protocollo HTTP.
L’applicazione dei suddetti metodi torva gestione, mediante il protocollo HTTP, di dati su cui vengono eseguite quelle operazioni definite come CRUD(CREATE,READ,UPDATE,DELETE).
Realizzare una REST API con Nodejs ed Express: cosa ci serve
Prima di proseguire dovete installare l’ultima versione di Node dall’indirizzo: https://nodejs.org/it/, non entro nello specifico in quanto mi aspetto che sappiate già di cosa si tratti e perchè si usa. Quindi vi consiglio di utilizzare un buon ide come visual studio code il quale è anche gratuito e non guasta.
Bene quindi aprite Visual Studio, fate clic su ctrl+ò , si apre il terminale. Da terminale digitate :
npm -v
e
node -v
se vi ritorna:
lucio@LENOVO MINGW64 /h/APP/REACT/react-redux-corse-master/nasdaq $ npm -v 6.14.14 lucio@LENOVO MINGW64 /h/APP/REACT/react-redux-corse-master/nasdaq $ node -v v14.17.5 lucio@LENOVO MINGW64 /h/APP/REACT/react-redux-corse-master/nasdaq $
bene abbiamo verificato che Node è stato installato correttamente.
Realizzare una REST API con Nodejs ed Express: imposta il progetto
Scegliete una directory a piacere nel vostro pc ed apritela con Visual studio code, quindi aprite il terminale ed inizializzate il progetto digitando:
npm init -y
noterete che verrà aggiunto il file package.json con le info relative al progetto, autore,versione ecc..
package.json:
{ "name": "NODEJS_EXPRESS", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC" }
Ora installa il framework Express, da terminale ed all’interno della root del progetto digita:
npm install express
Crea un End point
Faremo un test costruendo una piccola App che ritornerà il messaggio “Hello world”, una volta aperta nel browser.
Apri il terminale nella root principale del progetto e digita:
touch test.js
con questo comando abbiamo creato il file test.js all’interno del progetto, al suo interno inserisci le seguenti dichiarazioni:
const express = require('express'); const app = express(); const port = 3000;
in pratica importiamo express all’interno di esso, inizializiamo la constante app con esso ed impostiamo la porta 3000 dove avviare il server.
Ora siamo in grado di realizzare un end point GET. Una volta in cui l’utente la richiamerà visualizzerà il messaggio “Hello world, from express”:
const express = require('express'); const app = express(); const port = 3000; app.get('/', (req, res)=> { res.send('Hello world, from express') })
lo ‘/’ indica il percorso da aprire , in questo caso è la Home page del sito.
Inizializzare il client
Ora non ci resta che inizializzare il client, sempre nel file test.js di seguito digita:
... app.listen(port, () => console.log(`Hello world app listening on port ${port}`))
ora mandiamo l’applicazione in esecuzione e possiamo visualizzare il risultato nel browser, da terminale digita:
lucio@LENOVO MINGW64 /h/APP/NODEJS_EXPRESS $ node test.js
apri il browser all’indirizzo: http://localhost:3000/, dove il 3000 corrisponde all’impostazione della porta della costante port(potremmo cambiarla se volessimo, nel caso in cui fosse già occupata)
Utilizzare i Middleware con Express
I Middleware sono delle estensioni del server Express che aggiungono funzionalità le quali agiscono nelle richieste. Per iniziare installiamo un Middleware in grado di decodificare il corpo di una richiesta HTTP: body-parser.
Da terminale e dalla root principale del progetto aprite il terminale e digitate:
npm install body-parser
con questo comando installeremo body-parser come dipendenza difatti se ora aprite il file package.json vi troverete:
... }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "body-parser": "^1.19.0", "express": "^4.17.1" } } ...
Un altro Middleware molto utile è CORS (cross-origin-resource sharing), da terminale installatelo come dipendenza:
npm install cors
questo ci risolve il problema legato alla condivisione di informazioni tra le origini di due risorse che risiedono in server diversi.
Realizzare le API REST
Per iniziare implementiamo la possibilità di aggiungere , nel nostro caso, libri al database, quindi rinomina il file test.js in index.js e di seguito modifica il file index.js:
const express = require('express'); const cors = require('cors') const app = express(); const port = 3000; let books = [] app.use(cors()) app.use(express.urlencoded({extended: false})) app.use(express.json()) //RICHIESTA GET app.get('/', (req, res)=> { res.send('Hello world, from express') }) //AGGIUNGI LIBRI POST app.post('/book',(req,res) => { const book = req.body console.log(book) books.push(book) res.send('Book is added to the database') }) app.listen(port, () => console.log(`test app listening on port ${port}`))
spiegazione del codice:
come vedete non importa importare body-parser in quanto a partire dalla versione 4.16 di express è stato deprecato il suo utilizzo per cui utilizzo app.use(express.urlencoded({extended: false})) e app.use(express.json()) per decodificare la richiesta HTTP.
Con let books = [] inizializzo un array vuoto relativo ai libri
quindi aggiungo il metodo app.post… che ci consente di aggiungere libri al database.
Realizza un form in html
Per poter aggiungere i libri nel db abbiamo bisogno di un form , quindi, in una directory a parte, create il file new-book.html e grazie all’attributo action possiamo passare il valore dell’API:
FRONT-END/new-book.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css" integrity="sha384-B0vP5xmATw1+K9KRQjQERJvTumQW0nPEzvF6L/Z6nronJ3oUOFUFpCjEUQouq2+l" crossorigin="anonymous"> <title>Add books</title> </head> <body> <div class="container"> <h2 class="text-center">Add book</h2> <form action="http://127.0.0.1:3000/book" method="POST"> <div class="form-group"> <label for="ISBN">ISBN</label> <input type="text" class="form-control" id="ISBN" aria-describedby="emailHelp" placeholder="Enter ISBN" name="isbn"> </div> <div class="form-group"> <label for="title">Title</label> <input type="test" class="form-control" id="title" placeholder="Title" name='title'> </div> <div class="form-group"> <label for="author">Author</label> <input type="text" class="form-control" id="author" placeholder="Author" name="author"> </div> <div class="form-group"> <label for="Published date">Published date</label> <input type="text" class="form-control" id="publish_date" placeholder="Published date" name="publish_date"> </div> <div class="form-group"> <label for="Publisher">Publisher</label> <input type="text" class="form-control" id="Publisher" placeholder="Publisher" name='publisher'> </div> <div class="form-group"> <label for="Number of pages">Number of pages</label> <input type="text" class="form-control" id="Number of pages" placeholder="Number of pages" name='numOfPages'> </div> <button type="submit" class="btn btn-primary">Submit</button> </form> </div> <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.min.js" integrity="sha384-+YQ4JLhjyBLPDQt//I+STsc9iw4uQqACwlvpslubQzn4u2UU2UFM80nGisd026JF" crossorigin="anonymous"></script> </body> </html>
niente di eccezionale, un semplice form html utilizzando il framework bootstrap per renderlo più carino.
Come potete notare all’interno dell’attributo action inserisco il percorso dell’Api responsabile dell’aggiunta di libri.
Piccolo trick relativo all’avvio del server in node, innanzitutto per chiudere il server fate ctrl+c.
Visto che abbiamo il file package.json possiamo impostare quest’ultimo per avviare il server aggiungendo nel nodo script la seguente riga:
... "scripts": { "start": "node index.js", "test": "echo \"Error: no test specified\" && exit 1" }, ...quindi da terminale per avviare il server ci basterà digitare npm start.
Ma non è tutto, in questo momento ogni volta che apportiamo modifiche ai file di node, per vederne gli effetti, dobbiamo ‘killare’ ed avviare il server. Per evitare ciò ci viene in aiuto un package chiamato nodemon, quindi da terminale installiamolo come devDependencies, digitate:
npm install -D nodemonquindi nel file package.json aggiungete, sempre nel nodo scripts:
... "dev": "nodemon index.js", ...ora se avviate il server con il comando da terminale:
npm run devdovreste vederne gli effetti:
lucio@LENOVO MINGW64 /h/APP/NODEJS_EXPRESS $ npm run dev > nodejs_express@1.0.0 dev H:\APP\NODEJS_EXPRESS > nodemon index.js [nodemon] 2.0.14 [nodemon] to restart at any time, enter `rs` [nodemon] watching path(s): *.* [nodemon] watching extensions: js,mjs,json [nodemon] starting `node index.js` test app listening on port 3000
Ora provate a riempire il form e a dare invio, se tutto è andato bene dovreste essere reindirizzati in una pagina che vi conferma l’inserimento del libro nel database:
quindi:
inoltre se visionate il terminale vi è la risposta della console:
lucio@LENOVO MINGW64 /h/APP/NODEJS_EXPRESS $ npm run dev > nodejs_express@1.0.0 dev H:\APP\NODEJS_EXPRESS > nodemon index.js [nodemon] 2.0.14 [nodemon] to restart at any time, enter `rs` [nodemon] watching path(s): *.* [nodemon] watching extensions: js,mjs,json [nodemon] starting `node index.js` test app listening on port 3000 [Object: null prototype] { isbn: '4023568974', title: 'The art of war', author: 'Sun Zu', 'Published date': '22/10/2021', publisher: '22/10/22', 'number of pages': '120' }
Estrarre i dati inseriti
Benissimo non ci rimane che realizzare l’end point responsabile di estrarre tutti i libri inseriti quindi nel file index.js aggiungi il metodo:
... //RITORNA LISTA LIBRI app.get('/book',(req,res)=> { res.json(books) })
quindi collegati all’indirizzo http://localhost:3000/book e vedrai:
Visualizza i libri nel browser
Nella directory relativa ai file html crea /FRONT-END/list-book.html ed inserisci:
<!DOCTYPE html> <html lang="it"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css" integrity="sha384-B0vP5xmATw1+K9KRQjQERJvTumQW0nPEzvF6L/Z6nronJ3oUOFUFpCjEUQouq2+l" crossorigin="anonymous"> <title>List of books</title> </head> <body> <div class="container"> <hr> <h1>List of books</h1> <hr> <div> <div class="row" id="books"> </div> </div> </div> <div id="editBookModal" class="modal" tabindex="-1" role="dialog"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title">EDIT BOOK</h5> <button type="button" class="close" data-dismiss='modal' aria-label='Close'> <span aria-hidden="true">×</span> </button> </div> <div class="modal-body"> <form action="" id="editForm" method="post"> <div class="form-group"> <label for="ISBN">ISBN</label> <input type=" text" class="form-control" name="isbn" id="isbn"> </div> <div class="form-group"> <label for="title">Title</label> <input type="test" class="form-control" id="title" placeholder="Title" name='title'> </div> <div class="form-group"> <label for="author">Author</label> <input type="text" class="form-control" id="author" placeholder="Author" name="author"> </div> <div class="form-group"> <label for="Publisher">Publisher</label> <input type="text" class="form-control" id="publisher" placeholder="Publisher" name='publisher'> </div> <div class="form-group"> <label for="Published date">Published date</label> <input type="text" class="form-control" id="publish_date" placeholder="Published date" name="publish_date"> </div> <div class="form-group"> <label for="Number of pages">Number of pages</label> <input type="text" class="form-control" id="numOfPages" placeholder="Number of pages" name='numOfPages'> </div> <button class="btn btn-primary">Submit</button> </form> </div> </div> </div> </div> <script src="book-list.js"></script> <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.min.js" integrity="sha384-+YQ4JLhjyBLPDQt//I+STsc9iw4uQqACwlvpslubQzn4u2UU2UFM80nGisd026JF" crossorigin="anonymous"></script> </body> </html>
con il suddetto codice dovreste vedere la lista dei libri nel browser anche se ancora manca da implementare il file js, quindi createlo book-list.js:
const setEditModal = (isbn) => { // implement } const deleteBook = (isbn) => { // implement } const loadBooks = () => { const xhttp = new XMLHttpRequest(); xhttp.open("GET","http://localhost:3000/books",false) xhttp.send(); const books = JSON.parse(xhttp.responseText); for(let book of books){ const x = ` <div class="col-4"> <div class="card"> <div class="card-body"> <h5 class="card-title">${book.title}</h5> <h6 class="card-subtitle mb-2 test-muted">${book.isbn}</h6> <div>Author: ${book.author}</div> <div>Publisher: ${book.publisher}</div> <div>Numb of pages: ${book.numOfPages}</div> <hr> <button type="button" class="btn btn-danger">DELETE</button> <button types="button" class="btn btn-primary" data-toggle="modal" data-target="#editBookModal" onClick="setEditModal(${book.isbn})"> EDIT </button> </div> </div> </div> ` document.getElementById('books').innerHTML = document.getElementById('books').innerHTML + x; } } loadBooks();
come vedete ho già inserito i metodi relativi al modal di bootstrap ed alla cancellazione del libro, quindi un ciclo for per leggere ed estrare i libri dall’Array.
Mostrare i dettagli di un libro tramite il suo codice Isbn
Come di certo saprete per mostrare il dettaglio di uno specifico, nel nostro caso, libro occorre un codice univoco di solito dato dall’id dell’elemento interessato. Noi sfrutteremo il codice Isbn, anche questo univoco del prodotto, come nel caso persone il codice fiscale 😉 😉
Quindi ad esempio, una volta implementato il metodo per il dettaglio, nella url del browser andremo ad inserire l’indirizzo relativo ai libri comprensivo di codice Isbn: http://127.0.0.1:3000/book/4023568974 dove 4023568974 è l’Isbn quindi il codice univoco del libro.
Ora aprite il file index.js dell’end point ed inserite:
... //MOSTRA DETTAGLIO LIBRO app.get('/book/:isbn',(req, res)=> { const isbn = req.params.isbn; for (let book of books){ if(book.isbn === isbn){ res.json(book) return; } } res.status(404).send('Book not found'); }) ...
Ok se tutto è corretto inserite l’indirizzo http://127.0.0.1:3000/book/4023568974 (voi mettete il vostro codice isbn ovviamente) e vi dovreste trovare una pagina simile a questa:
Cancella Libri
Pr concludere la nostra REST FULL Api non ci resta che implementare il metodo DELETE dello stesso.Lofaremo tramite richiesta HTTP DELETE quindi aprite il file index.js ed inserite:
... //CANCELLA LIBRO METODO DELETE app.delete('/book/:isbn', (req, res) => { const isbn = req.params.isbn; books = books.filter(i =>{ if(i.isbn !== isbn){ return true; } return false; }) res.send('Book is deleted') }) ...
Quindi riepilogando tramite il metodo app.delete viene accettata la richiesta DELETE e, tramite il metodo javascript filter dell’array dei libri per cancellare quello con l’isbn richiesto.
Il metodo
filter()
dell’oggettoArray
è stato introdotto in ECMAScript 5 e serve ad eseguire una routine all’interno di una funzione di callback su ciascuna voce di un array restituendo un nuovo array le cui voci sono il risultato del soddisfacimento di un’operazione booleana
Ora non rimane che implementare il metodo deleteBook lasciato in sospeso nel file book-list.js:
... const deleteBook = (isbn) => { const xhttp = new XMLHttpRequest(); xhttp.open("DELETE", `http://localhost:3000/book/${isbn}`, false) xhttp.send(); location.reload(); } ...
La richiesta avverrà una volta premuto il pulsante Delete nella lista dei libri, proviamo.
Modificare i Libri
Modifica ed aggiornamento degli elementi di un array segue la stessa logica della cancellazione, nel senso che andremo a filtrare il libro scelto. I metodi da utilizzare sono PUT o POST per inviare nuove informazioni.
Aprite il file index.js ed implementate:
//MODIFICA LIBRO METODO POST app.post('/book/:isbn', (req, res) => { const isbn = req.params.isbn; const newBook = req.body; for(let i = 0; i < books.length; i++){ let book = books[i] if(book.isbn = isbn){ books[i] = newBook; } } res.send('Book is edited') })
Tramite la richiesta POST il libro con lo specifico codice isbn verrà aggiornato con le nuove informazioni inserite.
Per testarne il funzionamento dobbiamo implementare il metodo setEditModal nel file book-list.js:
... const setEditModal = (isbn) => { const xhttp = new XMLHttpRequest(); xhttp.open("GET", `http://localhost:3000/book/${isbn}`, false) xhttp.send(); const book = JSON.parse(xhttp.responseText); const { title, author, publisher, publish_date, numOfPages } = book; alert(publish_date) document.getElementById('isbn').value = isbn; document.getElementById('title').value = title; document.getElementById('author').value = author; document.getElementById('publisher').value = publisher; document.getElementById('publish_date').value = publish_date; document.getElementById('numOfPages').value = numOfPages; document.getElementById('editForm').action = `http://127.0.0.1:3000/book/${isbn}`; } ...
Ok se il codice funziona dovresti essere in grado di modificare i dati del libro ed essere reindirizzato su una pagina di conferma.
Realizzare una REST API con Nodejs ed Express: Conclusioni
Grazie a questa mini guida hai imparato a sviluppare una REST FULL Api con Nodejs ed Express partendo da zero. Sappi che il framework Express può essere utilizzato anche per altri scopi differenti da quelli visti nel corso del tutorial.
Puoi scaricare l’intero codice dal mio repository su Git Hub.
Se volete Approfondire le conoscenze su REACT E NODEJS CON EXPRESS E MONGODB potete seguire il corso completo su Udemy sempre scontato a 9.99/12.99 € , inoltre, nel momento in cui non foste soddisfatti, avete la possibilità di ottenere il rimborso completo dello stesso entro 30 giorni dalla data di acquisto!