fbpx

FrontEnd e BackEnd con NodeJS e VueJS


27 Set 2021 - Informatica, Software


FrontEnd e BackEnd con NodeJS e VueJS

Frontend e backend con NodeJS e VueJS. In questo articolo volevo mostrarti come creare una API con NodeJS e gestirla con VueJS. Creeremo una service con systemctl per demonizzare il nostro script NodeJS e gestiremo la parte front-end con VueJS. Questo articolo non ha la pretesa di essere un tutorial o un articolo didattico. Certo può aiutare a capire meglio il concetto di backend e frontend, di api e middleware ma in sostanza vuole essere il modo di condividere una passione e la soddisfazione unica e particolarissima che solo l’informatica e la programmazione possono dare.

FrontEnd e BackEnd con NodeJS e VueJS: Una introduzione!


L’idea di questo progettino è nato in un pomeriggio mentre configuravo un server linux di un amico con Plex.
Se segui il link su Plex puoi scoprire di cosa si tratta ma se ti annoi a leggere tutto l’articolo ti basti sapere che è una piattaforma che ti permette di avere in stile Netflix i tuoi video personali. Puoi farti un giro sul loro sito per avere un’idea più completa di ciò che fa!
Mi sono chiesto…e se scrivessimo noi da zero una nostra applicazione che faccia lo stesso?
Così ho buttato giù queste semplici righe di codice sicuramente migliorabili. Tuttavia può essere uno spunto di riflessione interessante per chi si approccia per la prima volta alla programmazione. Soprattutto per capire i concetti di backend e frontend e come le due realtà comunicano tra di loro.

L’idea di base: Cosa farà la webapp?


In buona sostanza ci sarà uno script su un server linux con installato NodeJS il quale leggerà il contenuto di una cartella periodicamente e tramite ExpressJS creerà delle API per rendere fruibile il contenuto di quella cartella.
Verrà generata una GET che sostanzialmente fornirà il path del file.
In VueJS gestiremo la vista di questi dati e grazie all’HTML5 e al tag video utilizzeremo i link che arriveranno dalla API di Node per visualizzare il filmato.
Ricordo che per i codec supportarti dai vari Browser è bene consultare la documentazione (https://www.w3schools.com/tags/tag_video.asp) comunque per andare sul sicuro consiglio di provare con degli mp4.

Se non hai un server linux e non ti interessa averne uno ma vuoi comunque sperimentare puoi comunque farlo.

Il materiale per il lavoro: Di cosa avremo bisogno!


Di cosa avrai bisogno per il tuo portale Netflix personale!
Scarica e installa NodeJS da qui se sei in Windows.
E’ il primo passo per iniziare a creare il tutto. Infatti inizieremo a configurare il lato backend. Ci preoccuperemo dopo dell’interfaccia utente.
Se hai un server linux e vuoi installare Node sulla tua macchina ti rimando a una guida esterna https://www.geeksforgeeks.org/installation-of-node-js-on-linux/.
Se hai una distro basata su debian sono veramente quattro comandi in croce.
Questa è un’altra guida se il tuo SO utilizza yum invece di aptitude : https://linuxize.com/post/how-to-install-node-js-on-centos-7/.
Apri una directory, o una cartella se sei in Win e crea un file con un nome a tua scelta ed estenzione .js oppure per semplificare le cose chiamalo direttamente index.js.
Così quando darai il comando per inizializzare il progetto non avrai difficoltà.

Frontend e Backend con NodeJS e VueJS: Inizializziamo il nostro Backend!


Portatevi nella directory appena creata. In Windows puoi aprire la cartella e nella barra degli indirizzi puoi eliminare l’intero path e digitare cmd. Si aprirà automaticamente il terminale all’interno della directory.
Dunque per inizializzare il progetto dai il comando:

npm init

Node ti chiederà un pò di cose e genererà un file chiamato package.json.

output del comando npm init
output del comando npm init

Per lasciare i settings di default suggeriti da Node puoi premere Invio. Come vedi alla voce “entry point” tra parentesi suggerisce “index.js“. Fai attenzione a quella voce! Se hai creato il tuo file prima di lanciare il comandi npm init suggerirà appunto il nome del tuo file, quello che hai creato insomma.
Se dimentichi di creare prima il file e lanci prima il comando npm init ricordati di cambiare il nome del tuo file.js nel package.json alla voce “main”:”index.js”, o di creare un file index.js nella root del tuo progetto.

Siamo pronti!!! Apriamo il nostro editor preferito e andiamo di codice JS per creare il nostro script con node JS.

Anzi no… ancora no! Abbiamo bisogno di installare con l’npm i nostri middleware.

Il middleware: Cos’è?


Il middleware, semplicisticamente, è ciò che sta tra il backend ed il frontend…”middle“! Agisce in sostanza come uno strato connettivo tra applicazione, dati e utenti. E’ l’intermediario tra diverse applicazioni e componenti software.
Nel nostro caso abbiamo un software sul nostro serverino che si preoccupa di leggere i dati nella cartella e un software sul browser del nostro utente.
Come facciamo a far comunicare i due software? Con i middleware, appunto.

Quelli che a noi servono sono expressJS, path e qualche altra cosina tipo cors per Cross-Origin Resource Sharing.

ExpressJS è ciò che ci serve per generare della API! Path è per gestire i percorsi, i path appunto.

Invece se non ci fossero i cors non funzionerebbero le chiamate HTTP che faremo con Axios, un parente di Ajax usato in VueJS.

“Si parla di  cross-origin HTTP request (CORS) quando un client richiede una risorsa di un differente dominio, protocollo o porta. Ad esempio una web application con dominio X non può richiedere una risorsa ad un dominio Y tramite AJAX request se Y non ha abilitato il CORS.” (fonte https://italiancoders.it/cors-in-dettaglio/).

npm install express --save
npm install path --save
npm install cors --save

Il “–save” si utilizza per accodare la dipendenza nel file package.json.

Il Backend: Il nostro script NodeJS!


Andiamo a vedere nel dettaglio il nostro file.js. Metterò tutto il codice qui sotto poi lo spezzetterò e ti spiegherò pezzo pezzo cos’è che fa.

const express = require('express');
const app = express();
const cors = require('cors');
const fs = require('fs');
const path = require('path');

const testFolder = `${__dirname}/movies/`;

let portaAscolto = 8089; //o una qualsiasi altra porta di ascolto libera
let ipAddress ='indirizzo_ip_della_tua_macchina';
let arrayPaths = [];
let n = 0;

app.use(cors());

function lettura() {
    
    array = [];
    let data = new Date();

    console.log('........................ \n');
    fs.readdir(path.resolve(testFolder), (err, files) => {
        files.forEach((file,id) => {
            app.get(`/api/${file}`, (req, res) => {
                res.download(`${testFolder}${file}`);
            });
            console.log(`Path : ${id} -> ${testFolder}${file}`);
        });
        console.log('\n........................ \n');


        n++;

        files.forEach((file, id) => {
            arrayPaths.push({ id: id, titolo: file.replace(/_|-|\.[^/.]+$/g, " "), path:`${ipAddress}:${portaAscolto}/api/${file}` });
        });

        console.log(`Numero file nella cartella : ${array.length}`);

        array.forEach((item, id) => {
            console.log(`PosizArray: ${id} - Nome file: ${item.titolo} - Path : ${item.path}`)
        })
        console.log(`Lettura effettuata ${n} volte alle ${data.getHours() < 10 ? '0' + data.getHours() : data.getHours()}:${data.getMinutes() < 10 ? '0' + data.getMinutes() : data.getMinutes()}:${data.getSeconds() < 10 ? '0' + data.getSeconds() : data.getSeconds()}`);

    });
};

lettura();

app.get('/paths', (req, res) => {
    res.send(array);
})

setInterval(function () {
    lettura();
}, 180000)

app.listen(portaAscolto, () => { console.log(`Servizio attivo sulla porta ${portaAscolto}`) });

La prima parte del codice è costituito da :

const express = require('express');
const app = express();
const cors = require('cors');
const fs = require('fs');
const path = require('path');

Niente di particolarmente complicato. Stiamo andando a “richiedere” l’utilizzo dei pacchetti installati in precedenza. Express, Cors, il modulo Fs per la lettura dei file e Path.
Per utilizzare Express è necessario utilizzare il metodo express(). Per comodità creiamo una variabile app con valore express() per evitare di scriverlo ogni volta!


const testFolder = `${__dirname}/videos/`;

let portaAscolto = 8089; //o una qualsiasi altra porta di ascolto libera
let ipAddress ='indirizzo_ip_della_tua_macchina';
let arrayPaths = [];
let n = 0;

Qui invece abbiamo una costante nella prima riga che indica il percorso dove andare a leggere il contenuto della cartella.
__dirname è una variabile d’ambiente che ti dice il percorso assoluto della directory contenente il file attualmente in esecuzione.
Infatti la cartella “videos” ti consiglio di aggiungerla nella root della cartella del progetto!

Le altre due variabili “portaAscolto” ed “ipAddress” sono abbastanza esplicite! Ci serviranno dopo per ExpressJS e generare i link api.

Invece arrayPaths è variabile che conterrà l’elenco dei file che il modulo fs troverà nella nostra caretellina “videos“. La variabile “n” è semplicemente un contatore. Ogni tot di tempo verrà rifatta la lettura della cartella per controllare eventuali cambiamenti dei file nella stessa.
Se ad esempio rinomini un file, o lo cancelli, o ne aggiungi uno nuovo.


app.use(cors());

function lettura() {
    
    array = [];
    let data = new Date();

    console.log('........................ \n');
    fs.readdir(path.resolve(testFolder), (err, files) => {
        files.forEach((file,id) => {
            app.get(`/api/${file}`, (req, res) => {
                res.download(`${testFolder}${file}`);
            });
            console.log(`Path : ${id} -> ${testFolder}${file}`);
        });
        console.log('\n........................ \n');


        n++;

        files.forEach((file, id) => {
            array.push({ id: id, titolo: file.replace(/_|-|\.[^/.]+$/g, " "), path:`${ipAddress}:${portaAscolto}/api/${file}` });
        });

        console.log(`Numero file nella cartella : ${array.length}`);

        array.forEach((item, id) => {
            console.log(`PosizArray: ${id} - Nome file: ${item.titolo} - Path : ${item.path}`)
        })
        console.log(`Lettura effettuata ${n} volte alle ${data.getHours() < 10 ? '0' + data.getHours() : data.getHours()}:${data.getMinutes() < 10 ? '0' + data.getMinutes() : data.getMinutes()}:${data.getSeconds() < 10 ? '0' + data.getSeconds() : data.getSeconds()}`);

    });
};

lettura();

Entriamo nel vivo della situazione!
Nella prima riga indichiamo ad ExpressJS di utlizzare i CORS. Non dimenticare questa riga altrimenti potresti trovarti un errore del genere in console di chrome quando farei le chiamate api con VueJS. Non dimentichiamo che il Frontend è gestito da VueJS ed il Backend con NodeJS.

esempio di errore cors
Esempio di errore CORS

Frontend e Backend con NodeJS e VueJS: Analizziamo la funzione lettura();!


Dalla seconda riga abbiamo una funzione che ci toccherà analizzare pezzo per pezzo!
Vediamola insieme.

arrayPaths = [];
let data = new Date();

Dopo aver inizializzata la function ho fatto in modo che venga azzerato l’arrayPaths e generata una data.
L’array viene azzerato per evitare che ogni volta che venga letto il contenuto della cartella questo vada ad aggiungersi a quello precedetemente letto.
Se non c’è stato alcun cambiamento nella cartella l’array conterrà un elenco di nomi tutti uguali.
Per intenderci se all’interno della cartella c’è un file chiamato “pippo.mp4” ad ogni lettura della cartella NodeJS leggerà che c’è un file chiamato appunto “pippo.mp4” e lo aggiungerà all’array generando un doppione! E a noi questo non serve.


    console.log('........................ \n');
    fs.readdir(path.resolve(testFolder), (err, files) => {
        files.forEach((file,id) => {
            app.get(`/api/${file}`, (req, res) => {
                res.download(`${testFolder}${file}`);
            });
            console.log(`Path : ${id} -> ${testFolder}${file}`);
        });
        console.log('\n........................ \n');

I console log servono in sostanza per avere un feedback visivo sul terminale. Il cuore del tutto è quel fs.readdir.
Questo codice viene utilizzato per leggere in modo asincrono il contenuto di una determinata directory. 
E’ un metodo, una funzione, che prende come primo argomento il path ed una callback che restituisce un array di tutti i nomi di file nella directory.
Con un forEach andiamo a scorrere questo array e per ogni suo elemento andiamo a creare con express() le nostre API.
Infatti app.get è un metodo di ExpressJS per generare una GET ad un indirizzo HTTP. Per maggiori info : https://expressjs.com/it/guide/using-middleware.html.
Come secondo argomento la app.get ha una callback che gestisce la req e la res. Cioè la richiesta e la risposta. In questo caso abbiamo indicato che vogliamo essere risposti con il download del file indicato nel path testFolder!


Frontend e Backend con NodeJS e VueJS: Gestione della variabile arrayPaths!


  n++;

        files.forEach((file, id) => {
            arrayPaths.push({ id: id, titolo: file.replace(/_|-|\.[^/.]+$/g, " "), path:`${ipAddress}:${portaAscolto}/api/${file}` });
        });

        console.log(`Numero file nella cartella : ${array.length}`);

        array.forEach((item, id) => {
            console.log(`PosizArray: ${id} - Nome file: ${item.titolo} - Path : ${item.path}`)
        })
        console.log(`Lettura effettuata ${n} volte alle ${data.getHours() < 10 ? '0' + data.getHours() : data.getHours()}:${data.getMinutes() < 10 ? '0' + data.getMinutes() : data.getMinutes()}:${data.getSeconds() < 10 ? '0' + data.getSeconds() : data.getSeconds()}`);

n++ mi serve per incrementare quella variabile inizializzata come contatore! Verrà portata ad 1 in questo primissimo caso facendoci capire che è la prima volta che viene eseguita la funzione lettura.
A questo punto rifacciamo un forEach di quell’array generato dalla callback di fs.readdir e per ogni item dell’array andiamo a pushare nella nostra variabile arrayPaths un oggettino con chiavi id, titolo e path; e valori l’id appunto, il nome del file riformattato con regex eliminando gli underscore e l’estenzione del file (infatti ogni file nella cartella devi rinominarlo utilizzando questo_tipo_di_esempio.mp4) e il percorso del file letto precedentemente da fs.readdir.

Il resto del codice sono tutti console log per la lettura a video di ciò che succede e di ciò che viene passato alle API.


Frontend e Backend con NodeJS e VueJS: Ed infine…


lettura();

app.get('/paths', (req, res) => {
    res.send(array);
})

setInterval(function () {
    lettura();
}, 180000)

app.listen(portaAscolto, () => { console.log(`Servizio attivo sulla porta ${portaAscolto}`) });

Alla fine del file eseguo la funzione lettura(); poi con app.get invio all’indirizzo_macchina:porta_di_ascolto/paths la mia variabile array (quella che ho inizializzato in cima alla lista per intenderci e dove ho pushato l’oggettino con chiave id,titolo,path.
Infine ogni 180000 millisecondi (pari a tre minuti) verrà ripetuta la funzione function(); aggiornando eventualmente l’arrayPaths.
app.listen mette in ascolto sulla porta assegnata il servizio e lo rende fruibile dall’esterno come API.

Backend: Demonizziamo il servizio


Se sei in Windows e vuoi testare il tutto ti basterà una volta assegnata la porta di ascolto e l’indirizzo ip della tua macchina (puoi utilizzare anche “localhost” se non vuoi farlo girare in rete) ti basterà dare il comando :

node nome_del_tuo_file.js

Altrimenti se sei in ambienti linux e preferisci demonizzare il servizio facendo in modo che node lo faccia funzionare sempre e ad ogni avvio di macchina dovrai creare un file service in /lib/systemd/system strutturato in questo modo:

Environment=NODE_PORT=la_porta_che_hai_scelto_nel_file_di_prima
Type=simple
User=il_tuo_user
ExecStart=/usr/bin/node /il/path/dove/hai/messo/il/file.js
Restart=on-failure

[Install]
WantedBy=multi-user.target

Non ti resterà salvarlo come, ad esempio, api_nodejs.service e dare i comandi:

systemctl enable api_nodejs.service && systemctl start api_nodejs.service

VueJS: VueJS e Axios


A questo punto abbiamo tutto ciò che ci serve nel backend per generare delle api che possiamo gestire con Axios, o Ajax.
Ho scelto di mostrartelo con VueJS in quanto è un framework che so utilizzare bene ed è molto semplice.

Non inserirò tutto il listato del componente in quanto puoi sbizzarrirti a randerizzare il tutto come meglio credi o come più ti aggrada! Utilizzando magari le cards di Boostrap o un carosello… insomma come meglio credi.

Naturalmente dovrai, una volta fatto partire un progetto VueJS installare Axios con:

npm install axios --save

La parte script del componente è questa :

<script>
import axios from "axios";
import { mapGetters, mapActions } from "vuex";
export default {
  name: "HelloWorld",
  data() {
    return {
      paths: null,
    };
  },
  computed: {
    ...mapGetters(["getPaths"]),
  },
  methods: {
    ...mapActions(["actPaths"]),
    saveInVuex() {
      this.actPaths(this.paths);
    },
    connection() {
      axios
        .get("http://il_tuo_ip:la_tua_porta/paths")
        .then(
          (response) => (
            (this.paths = response.data),
            console.log(this.paths),
            this.saveInVuex()
          )
        );
    },
  },
  mounted() {
    this.connection();
  },
};
</script>

Ho utilizzato Vuex per gestire gli stati ma tu puoi tranquillamente non utilizzarlo e seguire le linee guida di VueJS su come utilizzare Axios : https://vuejs.org/v2/cookbook/using-axios-to-consume-apis.html.

Ti basterà eliminare l’indirizzo dal .get ed inserire il tuo.

A quel punto puoi lavorare di fantasia e gestire al meglio i dati JSON che ti arriveranno. Puoi inserire nel tag video il valore che ti arriverà dall’api con chiave path per visualizzare il player e vedere il video salvato nella cartella del server.
La comodità e la cosa carina è che quando aggiungerai un nuovo file il server invierà un api aggiornata.
Controlla i codec dell’HTML5…ad esempio i file mp4 sono supportati dalla maggior parte dei browser.

Naturalmente una volta deployato il progettino in VueJS dovrai caricarlo e configurare il tuo server Apache2. Come fare lo vedremo in un altro tutorial. Ti basterà fare port forwarding sulla porta utilizzata sullo script node, sostituire al limite l’ip della macchina con un indirizzo ddns, e sulla porta 80 del servizio Apache e potrai raggiungere la tua webapp da qualsiasi rete!

Frontend e Backend con NodeJS e VueJS: Conclusioni


Come hai potuto vedere in questi semplici script i due mondi del Backend e del Frontend trovano un canale di comunicazione attraverso i Middleware.
Si potrebbe migliorare il tutto implementando MongoDB e salvando la variabile arrayPaths in un database. Ma questa è un’altra storia.
Può essere un esercizio divertente. Questo è solo un esempio di ciò che puoi fare, non ti resta che dare libero sfogo alla creatività e alla fantasia.

GiustinoRomano.IT – I do IT with my Heart.




Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *