Tutorial > Come creare un web server con Node.js su Ubuntu 20.04

Come creare un web server con Node.js su Ubuntu 20.04

Pubblicato il: 15 marzo 2021

Hosting Node.js Web Server

Introduzione

Quando visualizzi una pagina web sul tuo browser, stai effettuando una richiesta a un altro computer collegato a Internet, il quale te la fornisce come risposta: questo computer prende il nome di web server. Un web server riceve le richieste HTTP da un client, come il tuo browser, e fornisce una riposta HTTP. Esempi di risposte possono essere pagine HTML oppure JSON da un’API.

Diversi software vengono impiegati da un server per generare una riposta in forma di pagina web. Questi software ricadono generalmente in due categorie:

  • Front-end, con cui si fa riferimento a tutta quella parte di codice che determina l'interfaccia e il contenuto della pagina con cui interagisce l'utente, ovvero l’aspetto della UX (User Experience);
  • Back-end, che riguarda invece il modo in cui i dati vengono scambiati, processati e immagazzinati. Facile intuire quindi che le richieste di rete che vengono effettuate dal tuo browser, o le eventuali comunicazioni con il database, vengono principalmente trattate dal back-end.

Node.js permette agli sviluppatori di utilizzare JavaScript per scrivere codice back-end, anche se esso era tradizionalmente utilizzato nel browser per scrivere codice front-end. Avere sia il frontend che il backend insieme, come in questo caso, permette di ridurre notevolmente la mole di lavoro impiegata per creare un server web: questo è il motivo per cui Node.js è così utilizzato per scrivere codice back-end.

In questo tutorial, imparerai a costruire dei server web utilizzando il modulo HTTP che è già integrato in Node.js. Imparerai quindi a costruire web server in grado di restituire dati di tipo JSON, file CSV e pagine HTML.

Assicurati che Node.js sia installato sulla macchina che utilizzerai per lo sviluppo, se non lo hai ancora installato pui seguire la nostra guida su come installare Node.js su Ubuntu.

Per prima cosa dovrai connetterti al tuo server tramite una connessione SSH. Se non l’hai ancora fatto, ti consigliamo di seguire la nostra guida per connetterti in sicurezza con il protocollo SSH. In caso di server locale puoi passare al punto successivo e aprire il terminale del tuo server.

Creazione di un server HTTP di base

Muoviamo i primi passi creando un server che restituisca un semplice testo all’utente.

Questa prima parte di guida ti porterà a conoscere alcuni concetti chiave per l’impostazione di un serve. Considera questi concetti come delle fondamenta, che ti aiuteranno poi a creare server in grado di restituire formati di dati più complessi, come JSON ad esempio.

Come prima cosa, hai bisogno di creare il tuo ambiente di codifica per svolgere gli esercizi.

Crea una cartella chiamata “first-servers”:

$ mkdir first-servers

Successivamente, accedi alla cartella:

$ cd first-servers

Ora, crea il file che ospiterà il codice:

$ touch hello.js

Apri il file in un editor di testo. In questa guida utilizzeremo nano per comodità, ma sei libero di utilizzare il tuo editor preferito:

$ nano hello.js

É giunto ora il momento di caricare il modulo HTTP, considerato lo standard per Node.js. Aggiungi la seguente linea di codice al file precedentemente creato e aperto “hello.js”:

const http = require("http");

Questo modulo contiene le funzioni che ci serviranno a creare il server, lo vedremo tra pochissimo.

Vai ora a dichiarare due costanti, l’host e la porta, a cui il server dovrà collegarsi:

...
    const host = 'localhost';
    const port = 8000;

Come detto in precedenza, i web server accettano richieste da browsers e altri client. Puoi interagire con un web server inserendo il nome del dominio, che viene tradotto in un indirizzo IP da un server DNS. Un indirizzo IP è costituito da una sequenza unica di numeri, che identificano un elaboratore collegato alla rete.

Il valore localhost è un tipo di indirizzo privato speciale, esso viene utilizzato dal computer per riferirsi a sé stesso. Di solito, localhost è l’equivalente dell’indirizzo IP locale 127.0.0.1.

La porta invece è un numero che i server utilizzano come un punto di ingresso per il nostro indirizzo IP. Per esempio, in questa guida abbiamo deciso far riferimento alla porta 8000 per il nostro server web. Le porte 8080 e 8000, infatti, sono utilizzate come porte di default nello sviluppo, parlando di server HTTP.

Una volta collegato il nostro server a questo host (localhost) e a questa porta (8000), dovremmo essere in grado di raggiungerlo visitando http://localhost:8000 con un qualsiasi browser locale.

Aggiungi ora una funzione speciale, che in Node.js chiameremo request listener. Questa funzione si occupa di gestire una richiesta HTTP in arrivo, e di restituire poi una risposta HTTP.

La funzione necessita di almeno due parametri, un oggetto richiesta e un oggetto risposta. L’oggetto richiesta cattura tutti i dati della richiesta HTTP in arrivo. L’oggetto risposta, invece, viene utilizzato per restituire una risposta HTTP per il server.

Desideriamo che il nostro primo server restituisca questo messaggio a chiunque provi ad accedervi:

"Hello World!"

Aggiungi quindi la funzione in questo modo:

const requestListener = function (req, res) {
       res.writeHead(200);
       res.end("Hello World!");
    };

É preferibile che le funzioni abbiano dei nomi significativi: chiamale con qualcosa che ricordi quello che fanno. Ad esempio, se crei una funzione request listener per farti restituire una lista di libri, sarebbe opportuno che tu la chiamassi listBooks() magari. Siccome il nostro esempio è un caso generico, lascia pure come nome requestListener.

Tutte le funzioni request listener in Node.js accettano due parametri: req e res (che possono essere chiamati anche in maniera differente). Quindi, la richiesta HTTP mandata dall’utente viene catturata in un oggetto richiesta, che corrisponde al primo parametro, ovvero req. La riposta HTTP che restituiamo all’utente viene invece formata dall’interazione con l’oggetto risposta, che corrisponde al secondo parametro, ovvero res.

La prima linea res.writeHead(200); imposta il codice di stato HTTP della risposta. Il codice di stato HTTP indica quanto efficientemente una richiesta HTTP è stata gestita dal server. In questo caso, il codice di stato 200 corrisponde a "OK".

La linea subito dopo, res.end("Hello World!"); scrive la risposta HTTP al client che l’ha richiesta. Questa funzione fornisce tutti i dati che il server deve restituire: in questo caso, restituisce dati di tipo testuale.

Ora puoi finalmente creare il server e sfruttare la funzione requestListener:

const server = http.createServer(requestListener);
    server.listen(port, host, () => {
    console.log(`Server is running on http://${host}:${port}`);
});

Per terminare, salva ed esci da nano attraverso la combinazione di tasti CTRL+X.

Fermiamoci un attimo ad esaminare il codice, nella prima linea abbiamo creato un nuovo oggetto server attraverso createServer(), una funzione del modulo http. Questo server accetta quindi richieste HTTP e le passa alla nostra funzione requestListener().

Dopo aver creato il server, devi associarlo a un indirizzo di rete. Puoi farlo con il metodo server.listen(). Esso accetta tre parametri: port, host e una funzione di callback che si attiva quando il server si mette in ascolto.

Questi tre parametri in realtà sono opzionali, ma indicare esplicitamente quale porta e quale host vogliamo che un web server utilizzi è sempre una buona idea. La funzione di callback invece scrive un messaggio nella console in modo da farti capire quando il server inizia ad ascoltare le connessioni.

Nota bene: Anche se requestListener() non utilizza l’oggetto req, esso deve comunque essere il primo parametro della funzione.

Con meno di quindici linee di codice, hai già creato un server web. Per vederlo in azione, basta scrivere sulla console:

$ node hello.js

Visualizzerai quindi questo output:

Server is running on http://localhost:8000

Come avrai notato, la linea di prompt è scomparsa. Questo accade perché Node.js si arresta solo nel momento in cui incontra degli errori che causano un crash o un arresto immediato, oppure se decidiamo di terminare il processo Node.js in esecuzione sul server. Fino ad allora, Node.js resterà in esecuzione e non sarà possibile inserire nuovi comandi.

In una nuova finestra del terminale, devi comunicare con il server utilizzando cURL, uno strumento che consente di trasferire dati da e verso una rete. Inserisci il comando curl per effettuare una richiesta HTTP GET al server:

curl http://localhost:8000

Premi invio, e a questo punto il terminale ti dovrebbe mostrare il seguente output:

Hello World!

Ora conosci le basi che servono per la costruzione di un server, e hai capito anche come ottenere risposte da esso.

Vediamo più nel dettaglio cos’è successo nel momento in cui hai deciso di provare il server. Utilizzando cURL, hai mandato una richiesta di tipo GET all’indirizzo http://localhost:8000. Possiamo con certezza affermare che il server Node.js stia ascoltando le connessioni provenienti da quell’indirizzo. Cos’è successo subito dopo? Il server ha passato la richiesta alla funzione requestListener. La funzione ha restituito un testo con il codice di stato 200 (OK!). Il server ha poi trasferito questa risposta a cURL, tramite il quale il messaggio è stato mostrato a schermo.

Prima di continuare, esci dal server premendo la combinazione di tasti CTRL+C. Questo interrompe l’esecuzione del server e ti permette di scrivere nuove istruzioni sul terminale.

La risposta che ti restituisce web server può essere data da diversi tipi di formati. Prima abbiamo parlato di pagine HTTP e di dati JSON, ma possiamo ricevere anche dati XML o CSV. Infine, i server web possono restituire anche dati non testuali, come per esempio: dei PDF, dei file compressi (file zip), dati audio o video.

In questa guida, oltre al semplice testo che abbiamo visto prima, imparerai a restituire dati JSON, CSV e HTML.

Questi tre tipi di formati riguardano dati testuali, in gergo si dice text-based, e sono tra i formati più utilizzati per restituire informazioni sul web.

Passando ora a Node.js, devi:

  • Impostare il Content-Type delle risposte HTTP con il valore adatto;
  • Assicurarti che la funzione res.end() riceva i dati nel formato corretto.

Vediamo ora questo meccanismo in azione con alcuni esempi. La maggior parte delle differenze coi codici precedenti riguarderanno la funzione requestListener. Per la creazione dei files, ti faremo usare un template in modo da facilitare le cose.

Crea un nuovo file chiamandolo html.js.

Nel terminale, inserisci il seguente codice per generare il file:

$ touch html.js

Ora, apri il file con il solito editor:

$ nano html.js

Copia il codice template all’interno del file:

const http = require("http");

const host = 'localhost';
const port = 8000;

const requestListener = function (req, res) {};

const server = http.createServer(requestListener);
server.listen(port, host, () => {
    console.log(`Server is running on http://${host}:${port}`);
});

Come sempre, salva ed esci dal file con la combinazione di tasti CTRL+X.

Ora, crea altre due copie di questo file. La prima copia per restituire dati CSV come risposta HTTP:

$ cp html.js csv.js

La seconda copia invece per restituire dati JSON:

$ cp html.js json.js

Queste ulteriori copie, invece, le utilizzerai per i prossimi esercizi:

cp html.js htmlFile.js
cp html.js routes.js

Per ora, concentriamoci sulla restituzione di dati JSON.

Restituire JSON

JSON, è un formato di dati testuale, comunemente usato dalle APIs per ricevere e restituire dati.

Apri ora json.js con nano:

$ nano json.js

Modifica la funzione requestListener() ed imposta il valore adatto nella sezione Content-Type:

...
const requestListener = function (req, res) {
    res.setHeader("Content-Type", "application/json");
};
...

Il metodo res.setHeader() aggiunge un’intestazione HTTP alla risposta. Le intestazioni HTTP (HTTP Headers) costituiscono delle informazioni addizionali che viaggiano insieme a una richiesta o insieme ad una risposta. Il nostro metodo res.setHeader() accetta due parametri: il nome dell’intestazione e il suo valore.

L’intestazione Content-Type è utilizzata per indicare il formato dei dati che viene inviato con la richiesta o con la risposta. In questo caso il nostro Content-Type è application/json.

Ora, per restituire i dati JSON, modifica il file json.js come segue:

...
const requestListener = function (req, res) {
    res.setHeader("Content-Type", "application/json");
    res.writeHead(200);
    res.end(`{"message": "This is a json test."}`);
};
...

Come prima, stai dicendo all’utente che la restituzione dei dati è andata a buon fine con il codice di stato 200 (OK!). Questa volta, nella chiamata response.end(), il parametro contiene una stringa JSON.

Salva ed esci dal file json.js con CTRL+X. Ora, avvia il server con il comando node:

$ node json.js

In una nuova finestra del terminale, raggiungilo attraverso cURL:

$ curl http://localhost:8000

Dato invio, visualizzerai il seguente output:

{"message": "This is a json test."}

Hai ottenuto con successo una risposta JSON. Assicurati poi di arrestare l’esecuzione del server premendo contemporaneamente CTRL+C. Ora, vediamo come trattare i dati CSV.

Restituire CSV

Il formato file Comma Separated Values, abbreviato in CSV, è un formato di testo standard comune per dati tabulari. Nella maggior parte dei casi, ogni riga è separata da una nuova linea, e ogni elemento della riga è separato dal precedente con una virgola.

Apri ora il file csv.js nell' editor:

$ nano csv.js

Aggiungi queste linee di codice alla solita funzione requestListener:

...
const requestListener = function (req, res) {
    res.setHeader("Content-Type", "text/csv");
    res.setHeader("Content-Disposition", "attachment;filename=testcsv.csv");
};
...

Questa volta, Content-Type indica che verranno restituiti dei dati in formato CSV. La seconda intestazione prende il nome di Content-Disposition. Quest’intestazione dice al browser in che modo visualizzare i dati.

I browser scaricano automaticamente il file anche se l’intestazione Content-Disposition non è impostata. ti conviene utilizzarla per scegliere il nome del file. In questo caso, hai bisogno di segnalare al browser che questo file CSV deve essere scaricato. Subito dopo, comunica al browser che il nome del file è testcsv.csv.

Scriviamo i dati CSV nella risposta HTTP:

...
const requestListener = function (req, res) {
    res.setHeader("Content-Type", "text/csv");
    res.setHeader("Content-Disposition", "attachment;filename=testcsv.csv");
    res.writeHead(200);
    res.end(`id,name,email\n1,John Doe,[email protected]`);
};
...

Questa volta, però, la chiamata res.end() contiene una stringa CSV. Le virgole separano i valori in ogni colonna mentre il carattere che serve per creare una nuova linea (/n) separa le righe. Abbiamo due righe, una per l’intestazione della tabella e una per i dati.

Prova subito questo server nel tuo browser. Salva il file csv.js ed esci dall’editor con CTRL+X.

Esegui il server con Node.js con il commando:

$ node csv.js

In un’altra finestra del terminale, raggiungi il server con il solito cURL:

$ curl http://localhost:8000

La console ti mostrerà questo:

id,name,email
1,John Doe,[email protected]

Se visiti http://localhost:8000 nel browser, verrà scaricato un file CSV di nome tabletest.csv.

Usciamo dal server premendo CTRL+C.

Vediamo ora come restituire dati HTML.

Restituire HTML

HTML, HyperText Markup Language, è il formato più comune che si possa utilizzare quando vogliamo che gli utenti interagiscano tramite un web browser con il nostro server. Infatti, è stato creato proprio per strutturare contenuto web. I browsers, quindi, a loro volta, sono costruiti per visualizzare contenuto HTML.

Apri nuovamente il file html.js nell'editor:

$ nano html.js

Modifica, come al solito, la funzione requestListener modificando il Content-Type per una ottenere una risposta HTML:

...
const requestListener = function (req, res) {
    res.setHeader("Content-Type", "text/html");
};
..

Ora, restituisci il contenuto HTML all’utente aggiungendo queste linee di codice:

...
const requestListener = function (req, res) {
    res.setHeader("Content-Type", "text/html");
    res.writeHead(200);
    res.end(`<html><body><h1>This is an HTML content.</h1></body></html>`);
};
...

Aggiungi per prima cosa il codice di stato http. Poi, chiama la funzione response.end() con un parametro che contiene data HTML. Una volta effettuato l'accesso al server tramite il browser, visualizzeraiuna pagina HTML con una sola intestazione che recita "This is an HTML page.".

Salva ed esci dal file con CTRL+X. Ora, avvia il server con il comando :

$ node html.js

Vedrai la scritta Server is running on http://localhost:8000 una volta avviato il programma.

Visita la pagina http://localhost:800 sul browser per vedere il risultato.

Arresta l’esecuzione del server tramite CTRL+C.

Restituire una pagina HTML da un file

Vediamo ora come restituire risposte HTML caricando dei files, per ottimizzare il tutto.

In questo modo, non ti ritroverai delle stringhe molto lunghe nel codice di Node.js.

Per farlo, devi caricare il file (o i files) HTML con il modulo fs e usare le sue informazioni durante la scrittura della risposta HTTP.

Per prima cosa, devi creare un file HTML che il server preveda come risposta:

$ touch index.html

Successivamente, aprilo con un editor di testo:

$ nano index.html

La pagina sarà minimale. Aggiungi quindi questo codice al file:

<!DOCTYPE html>

<head>
    <title>My Web Page</title>
</head>

<body>
      <h1>Hello World!</h1>
      <p>This is served from an HTML file</p>
</body>

</html>
    

Questa pagina web mostrerà due linee di testo: "Hello World!" e "This is served from an HTML file.".

Puoi procedere salvando e chiudendo il file con CTRL+X. Passa adesso al codice del server.

Apri htmlFile.js nell’editor:

$ nano htmlFile.js

Importa il modulo fs:

const http = require("http");
 const fs = require('fs').promises;
...

Questo modulo contiene una funzione readFile() per caricare il file HTML.

Inizia modificando requestListener() in modo da leggere il file:

...
const requestListener = function (req, res) {
 fs.readFile(__dirname + "/index.html")
};
...

Utilizza il metodo fs.readfile() per caricare il file. Il suo parametro sarà __dirname + "/index.html". La varibile speciale __dirname contiene il percorso in cui viene eseguito il codice di Node.js. Subito dopo, ci inserisci /index.html per caricare il file HTML creato in precedenza.

Ora, restituisci la pagina HTML dopo averla caricata:

...
const requestListener = function (req, res) {
 fs.readFile(__dirname + "/index.html").then(contents => {
  res.setHeader("Content-Type", "text/html");
  res.writeHead(200);
  res.end(contents);
 })
};
...

Utilizza il metodo then() per gestire il caso in cui fs.readfile() restituisca correttamente i dati. Il parametro contents contiene i dati del file HTML.

Scrivi il codice di stato per indicare la corretta riuscita della richiesta. Infine, manda al client la pagina HTML che hai caricato, con i dati contenuti nella variabile contents.

Il metodo fs.readFile() potrebbe a volte fallire, quindi ti tocca gestire anche il caso in cui si vengano a presentare degli errori.

Aggiungi questo alla funzione requestListener():

...
const requestListener = function (req, res) {
 fs.readFile(__dirname + "/index.html").then(contents => {
  res.setHeader("Content-Type", "text/html");
  res.writeHead(200);
  res.end(contents);
 }).catch(err => {
  res.writeHead(500);
  res.end(err);
  return;
 });
};
...

Salva poi il file ed esci da nano con CTRL+X.

In pratica, stai trattando gli eventuali errori con il metodo catch(). Esso riceve gli errori che restituisce fs.readFile() ed imposta il codice di stato a 500, valore che indica l’incontro avvenuto con un errore, quest’ultimo verrà poi restiuito all’utente.

Ora, esegui il server con il comando:

$ node htmlFile.js

Nel browser web, visita http://localhost:8000 per visualizzare la pagina.

Esci dal server tramite CTRL+C e torna al terminale.

Quando scriviamo codice, non è molto efficiente caricare una pagina HTML per ogni richiesta HTTP. Sarebbe meglio caricare più files HTML all’avvio e salvarne il contenuto. Una volta caricati, puoi impostare il server in modo da ascoltare le richieste provenienti dall'indirizzo.

Restituire HTML più efficientemente

Al posto di caricare un file HTML per ogni richiesta, ora andremo a vedere come caricare tutti i files solo una volta e all’inizio.

Nel terminale, apri il file Node.js con un editor:

$ nano htmlFile.js

Inizia aggiungendo una varabile prima di creare la funzione requestListener:

...
let indexFile;
    
const requestListener = function (req, res) {
...

La variabile appena creata tratterrà i contenuti del file HTML.

Ora, riadatta la funzione requestListener(). Al posto di caricare il file, essa restituirà ora i contenuti di indexFile.

Effettua poi questi cambiamenti nella creazione del server:

...

const server = http.createServer(requestListener);
    
fs.readFile(__dirname + "/index.html").then(contents => {
    indexFile = contents;
    server.listen(port, host, () => {
     console.log(`Server is running on http://${host}:${port}`);
    });
})
.catch(err => {
    console.error(`Could not read index.html file: ${err}`);
    process.exit(1);
});

Salva ed esci da nano premendo CTRL+X.

Letto il file, i contenuti verranno salvati nella variabile indexFile. Avvia successivamente il server con il metodo listen(). La convenienza sta nel caricare il file prima di far partire il server. In questo modo, sei sicuro che la funzione requestListener() restituisca una pagina HTML dato che indexFile non è più una variabile vuota.

Anche il gestore di errori è cambiato, in meglio. Se non viene caricato il file, viene catturato il tipo di errore e viene stampato sulla console. La funzione exit() fa si che venga chiuso Node.js senza neanche aver fatto partire il server. In questo modo, si piò risolvere il problema e poi riprovare a far partire il server.

Hai creato quindi diversi web server che restituiscono diversi tipi di dati all’utente. Solo che, non hai mai chiesto all'utente che tipo dati restituire. Ora, ti mostreremo come far dipendere il tipo di dati restituiti dalle scelte dell'utente.

Gestire i percorsi utilizzando un oggetto di richiesta HTTP

La maggior parte dei siti che visiti, ti permettono di accedere a più risorse. Un esempio potrebbe essere un sistema di gestione di libri. Questo sistema non dovrebbe solo gestire i dati del libri, ma anche i dati degli autori per un’eventuale catalogazione o ricerca.

Anche se i dati dei libri e i dati degli autori si riguardano, sono due tipi diversi di oggetti. In questi casi gli sviluppatori codificano ogni oggetto con dei differenti endpoints (punti di arrivo) in modo da indicare all’utente con che tipo di dati sta interagendo.

Creeremo ora un server per una piccola libreria, che restituirà due tipi di dati. Se l’utente visita l’indirizzo del server /books, riceverà una lista di libri in JSON. Se invece decide di visitare l’indirizzo /authors, riceverà una lista di autori in JSON.

Riapri l'esempio di risposta JSON:

$ node json.js

In un altro terminale, effettua velocemente una richiesta cURL:

$ curl http://localhost:8000

Visualizzerai questo:

{"message": "This is a JSON response"}

Ora, prova un altro comando curl:

curl http://localhost:8000/todos

Dopo aver premuto invio, otterrete questo risultato:

{"message": "This is a test."}

Non avendo specificato niente per l’indirizzo URL che contiene anche /todos, Node.js restituisce lo stesso messaggio JSON di default.

Separa ora i tipi di dati che verranno restituiti, dipendentemente dall’URL inserito.

Come prima cosa, esci dal server con CTRL+C.

Ora, apri routes.js nell’editor:

$ nano routes.js

Comincia inserendo i dati JSON prima della funzione requestListener():

...
const books = JSON.stringify([
{ title: "The Picture of Dorian Gray", author: "Oscar Wilde", year: 1890 },
{ title: "Pride and Prejudice", author: "Jane Austen", year: 1813 }
    ]);
    
const authors = JSON.stringify([
{ name: "Oscar Wilde", countryOfBirth: "Ireland", yearOfBirth: 1854 },
{ name: "Jane Austen", countryOfBirth: "United Kingdom", yearOfBirth: 1975 }
    ]);
    ...

La variabile books contiene i dati JSON dei libri. Ogni libro ha un titolo o nome, un autore, e l’anno di pubblicazione.

La variabile authors contiene invece i dati JSON degli autori. Ogni autore ha un nome, una nazione di nascita e l’anno di nascita.

Ora che hai i dati da restituire, modifica la funzione requestListener() per restituirli ai percorsi corretti.

Per prima cosa, assicurati che ogni risposta del server abbia il Content-Type: adatto

...
const requestListener = function (req, res) {
 res.setHeader("Content-Type", "application/json");
}
...

Ora, restituisci dei dati JSON in base all’URL che l’utente visita. Crea uno switch statement sull’URL della richiesta:

...
const requestListener = function (req, res) {
 res.setHeader("Content-Type", "application/json");
 switch (req.url) {}
}
...

Per ottenere il percorso URL da un oggetto richiesta, hai bisogno di accedere alla proprietà url. Ora puoi aggiungere delle casistiche allo switch per restituire i dati JSON appropriati.

Lo switch in JavaScript ti permette di eseguire codice in base al valore di un oggetto o di un’espressione (ad esempio, il risultato di alcune operazioni matematiche).

Aggiungi il primo caso (case), quello che riguarda la lista di libri:

...
const requestListener = function (req, res) {
 res.setHeader("Content-Type", "application/json");
 switch (req.url) {
   case "/books":
    res.writeHead(200);
    res.end(books);
    break
 }
}
...

Come prima, imposta il codice di stato a 200 e restituisci il JSON dei libri. Aggiungi poi il secondo caso (case), quello che riguarda gli autori:

...
const requestListener = function (req, res) {
 res.setHeader("Content-Type", "application/json");
 switch (req.url) {
  case "/books":
   res.writeHead(200);
   res.end(books);
  break
  case "/authors":
   res.writeHead(200);
   res.end(authors);
  break
 }
}
...

Ora però, restituiamo i dati JSON che contengono la lista degli autori.

Per pensare proprio a tutto, puoi inserire un errore nel caso in cui l’utente scelga di accedere a un qualsiasi altro percorso che non corrisponda ai due precedenti. Aggiungi quindi un ulteriore caso, che prende il nome di caso di default:

...
const requestListener = function (req, res) {
 res.setHeader("Content-Type", "application/json");
  switch (req.url) {
   case "/books":
    res.writeHead(200);
    res.end(books);
   break
   case "/authors":
    res.writeHead(200);
    res.end(authors);
   break
   default:
    res.writeHead(404);
    res.end(JSON.stringify({error:"404 Error Resource not found"}));
  }
}
...

Utilizza quindi la parola chiave default in uno switch. Imposta il codice di stato 404, esso indica che l’URL inserito non è stato trovato. Successivamente, configura un oggetto JSON contenente un messaggio di errore.

Prova ora il server per vedere se funziona. In un altro terminale, inserisci questo comando per vedere se ti viene restituita la lista di libri:

$ curl http://localhost:8000/books

Dai invio per visualizzare:

[{"title":"The Picture of Dorian Gray","author":"Oscar Wilde","year":1890},{"title":"Pride and Prejudice","author":"Jane Austen","year":1813}]

Ora, prova a fare la stessa cosa per /authors. Quindi, scrivi sul terminale:

$ curl http://localhost:8000/authors

Visualizzerai questo output:

[{"name":"Oscar Wilde","countryOfBirth":"Ireland","yearOfBirth":1954},{"name":"Jane Austen","countryOfBirth":"United Kingdom","yearOfBirth":1775}]

Infine, prova con un URL sbagliato per vedere se ti viene restituito il messaggio di errore:

$ curl http://localhost:8000/notreal

Visualizzerai quindi:

{"error":"404 Error Resource not found"}

Ora, puoi uscire dal server con CTRL+C.

Hai quindi creato dei percorsi in base alle scelte dell’utente per restituire diversi dati. Hai inoltre creato una risposta di default come errore nel caso in cui l’utente inserisca un URL non valido.

Conclusioni

In questo tutorial, sei riuscito a creare una serie di server HTTP in Node.js. Sei partito da una risposta composta da un testo semplice. Poi, sei arrivato a farti restituire dai server diversi tipi di dati: JSON, CSV e HTML. Successivamente, hai imparato ad ottimizzare la restituzione di dati HTML e infine hai creato diversi percorsi con tipi di dati differenti da visualizzare in base alle scelte dell’utente.

Se vuoi approfondire i concetti che hai imparato in questa guida, ti consigliamo di leggere la documentazione ufficiale di Node.js che riguarda il modulo HTTP.