RESTFul API con node.js ed express.js – Parte 3

API scalabile node ed express  - nodeScalabile - RESTFul API con node.js ed express.js – Parte 3

Dopo la seconda parte dell’articolo, sono rimasto in debito della conclusione, che andrò a descrivere in questa terza parte.

In questa terza parte, introduciamo l’utilizzo delle classi nel routing delle chiamate.

Utilizzo delle classi nel routing

Nel callback delle funzioni di routing, sostituiamo la chiamata diretta con il riferimento al metodo della classe. Ma andiamo con ordine.

Partiamo creando all’interno del nostro progetto una sottocartella col nome della classe, al quale aggiungiamo il suffisso “Controllers”. Per esempio se vogliamo scrivere le funzioni che gestiscono la lista delle attività da fare (todo) procediamo così:

mkdir todosControllers
nano todosControllers/todos.js

Nel file scriviamo:

class TodosController {
     sayHello(req, res) {
        return res.status(200).send({
           success: 'true',
           message: 'Hello World!'
        });
      }
}
const todoController = new TodosController();
module.exports = todoController;

La classe TodosController presenta il metodo sayHello che restituisce il messaggio “Hello World!” Inoltre le ultime due righe permettono di attivare la classe ed esportare il modulo per poter essere utilizzato nel file del routing (o dovunque possa servire).

A questo punto nel file routes/index.js andiamo a sostituire nel routing il callback con la funzione della classe todosControllers, non prima però di aver importato la classe stessa nel file:

const todoController = require('../todosController/todos.js');

[..]

routing.get('/', todoController.sayHello);

Come si può vedere, la chiamate GET del routing risulta molto più pulita e semplice da leggere. Inoltre questo ci permette di scrivere metodi complessi all’interno delle classi.

Questo primo trittico di articoli, vuole essere un’introduzione alla scrittura delle API RESTFul. Vorrei arricchire la collezione di articoli sulle API RESTFul trattando argomenti come gli Swagger per la generazione automatica della documentazione e di un ambiente di test, la limitazione delle API e l’autenticazione, solo per citarne alcuni.

Seguici e condividi su:
onpost_follow  - icon Follow en US - RESTFul API con node.js ed express.js – Parte 3
Tweet  - en US Tweet - RESTFul API con node.js ed express.js – Parte 3
- en US save - RESTFul API con node.js ed express.js – Parte 3
Share  - en US share - RESTFul API con node.js ed express.js – Parte 3

PM2

Pm2  - PM2 - PM2

PM2 è un manager di processi per node.js, permette di eseguire applicazioni node.js, di monitorarle e loggarle.

Si installa facilmente con npm

npm install pm2 -g

Alcuni comandi utili. Visualizza i processi attivi:

pm2 ls

Esegue il file app.js e lo mantiene attivo in backgroud assegnandoli un nome:

pm2 start app.js --name ApiV1

Comandi per fermare, far ripartire o eliminare dai processi l’app

pm2 stop ApiV1
pm2 restart ApiV1
pm2 delete ApiV1

Monitora e mostra a video i log dell’app ApiV1

pm2 logs ApiV1
Seguici e condividi su:
onpost_follow  - icon Follow en US - PM2
Tweet  - en US Tweet - PM2
- en US save - PM2
Share  - en US share - PM2

RESTFul API con node.js ed express.js – Parte 2

API scalabile node ed express  - nodeScalabile - RESTFul API con node.js ed express.js – Parte 2

Nella prima parte dell’articolo RESTFul API con node.js ed express.js – Parte 1 abbiamo visto l’approccio per creare un servizio RESTFul con node.js ed express.js, dall’installazione delle librerie, al classico Hello World!

Oggi vediamo come migliorare la struttura delle nostre API in modo da renderla scalabile. Aggiungiamo un Middleware per ottimizzare i flussi di lavoro, per rendere più ordinato il codice ma sopratutto per renderlo scalabile.

Middleware

Il middleware è un insieme di funzioni che hanno accesso agli oggetti richiesta e risposta e vengono richiamate per l’esecuzione di specifiche operazioni;

Creiamo il Middleware per gestire il routing delle API, spostandolo da punto di accesso (app.js) dell’app.
All’interno della cartella del progetto, creo una sottocartella chiamata routes e al suo interno creo il file index.js, nel quale scrivo:

import express from 'express';

const router = express.Router();

Ho creato un gestore per il routing. Ora sposto dal file app.js a questo file il routing ed esporto questo gestore per poter essere utilizzato nell’intero progetto:

routing.get('/', function (req, res) {
   res.status(200).send({
      success: 'true',
      message: 'Hello World!'
   })
});
module.exports = router;

allo stesso modo nel file app.js, od ovunque mi serva, devo importare il gestore e usarlo nell’app:

const router = require('./routes/index.js');

app.use(router);

In questo modo si può vedere come risulti molto pulito il codice del file app.js:

const express   = require('express');
const bodyParse = require('body-parser');
const router    = require('./routes/routes.js');

const app  = express();
const PORT = 5000;

//Parse incoming request
app.use(bodyParse.json());
app.use(bodyParse.urlencoded({extended: false}));
app.use(router);


app.listen(PORT, () => {
    console.log(`server running on port ${PORT}`)
});

sfruttando le caratteristiche del Middleware otteniamo un punto di accesso chiaro e pulito, senza eccessive necessità di modifiche e possibilità di implementare il codice in modo ordinato.

const express = require('express');

const router = express.Router();

routing.get('/', function (req, res) {
  res.status(200).send({
    success: 'true',
    message: 'Hello World!'
  })
});
//Export Module
module.exports = router;

Nella prossima parte, andremo a vedere come implementare delle classi e le relative funzioni per distribuire e ottimizzare ulteriormente il codice. Tutto questo per arrivare ad avere una struttura altamente scalabile e replicabile per tutti i nostri progetti.

Seguici e condividi su:
onpost_follow  - icon Follow en US - RESTFul API con node.js ed express.js – Parte 2
Tweet  - en US Tweet - RESTFul API con node.js ed express.js – Parte 2
- en US save - RESTFul API con node.js ed express.js – Parte 2
Share  - en US share - RESTFul API con node.js ed express.js – Parte 2

RESTFul API con node.js ed express.js – Parte 1

RESTFul API Node.js  - RESTfulAPIs NodeJS - RESTFul API con node.js ed express.js – Parte 1

Le basi

Creo la cartella che contiene il progetto e creo il file app.js punto di origine dell’applicazione REST API.
Inizializzo il gestore di pacchetti npm col comando npm init, questo mi crea il file package.json che memorizza tutte le dipendenze delle librerie installate con la versione.
Installo la prima libreria, necessaria per la creazione del servizio:

npm install express --save

all’interno del file app.js scrivo il primo esempio di codice per testare il funzionamento:

const express = require('express');

// Set up the express app
const app = express();

app.get('/', function (req, res) {
  res.status(200).send({
    success: 'true',
    message: 'Hello World!'
  })
});
const PORT = 5000;

app.listen(PORT, () => {
  console.log(`server running on port ${PORT}`)
});

Per poter inviare informazioni in formato JSON alle API, è necessario installare la libreria body-parse:

npm install body-parser --save

importarla all’interno del progetto (app.js) e configurarla:

const body-parser = require('body-parser');

// Parse incoming requests data
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));

a questo punto le funzioni possono intercettare i valori passati nel body in formato JSON:

if(!req.body.title) {
   return res.status(400).send({
      success: 'false',
      message: 'title is required'
   });
}

questo per esempio verifica la presenza della chiave title all’interno del JSON e se non presente restituisce messaggio di errore.

Nel prossimo articolo vedremo come costruire un Middleware per gestire il routing delle chiamate alle API.

RESTFul API con node.js ed express.js – Parte 2

Seguici e condividi su:
onpost_follow  - icon Follow en US - RESTFul API con node.js ed express.js – Parte 1
Tweet  - en US Tweet - RESTFul API con node.js ed express.js – Parte 1
- en US save - RESTFul API con node.js ed express.js – Parte 1
Share  - en US share - RESTFul API con node.js ed express.js – Parte 1

API Gateway Mapping

API Gateway  - API Gateway Diagram - API Gateway Mapping

Quando si utilizza il sistema di API Gateway di AWS, a volte, si ha la necessità di integrare i dati in arrivo dalla chiamata (passati dall’utente) a dati fissi oppure si ha la necessità di riorganizzare i dati in modo differente per poi poterli passare alla funziona Lambda.
Tramite il linguaggio VTL (Velocity Template Language) è possibile strutturare la mappa di integrazione con logiche personalizzate. Vediamo un esempio di integrazione semplice, dove ad ogni parametro in arrivo dalla chiamata, corrisponde un parametro passato alla Lambda.

#set($payload = $util.parseJson($input.json('$')))
{
    "pin": "demo",
    "action": "managealarm",
    "type": "$input.path('$.type')",
    "eventid": "$input.path('$.eventid')",
    "userid": "$input.path('$.userid')"
}

Non sembra di molta utilità, poiché non è dinamico e vincolato a parametri fissi, ma serve principalmente per aggiungere alcune chiave/valore specifici della chiamata.
Sicuramente più interessante è la possibilità di rendere dinamica la costruzione del JSON da restituire alla Lambda.

#set($payload = $util.parseJson($input.json('$')))
{
    "pin": "demo",
    "action": "command",
    "comname": "nome comando",
    "type": 2,
    "code": "$input.path('$.code')",
    "userid": "$input.path('$.userid')",
    "values": {
        #foreach($body in $payload.entrySet())
            #if ($body.key == "values")
                #foreach($valu in $body.value.entrySet())
                "$valu.key": "$valu.value"#if($foreach.hasNext),#end
                #end
            #end
        #end
    }
}

In questo caso, oltre ai parametri aggiuntivi con chiave e valore fissi e a quelli con chiave fissa ma con valore dinamico, si può vedere la costruzione dell’oggetto values in modo dinamico e si possono anche introdurre dei controlli, per esempio se il dato è valorizzato.


http://velocity.apache.org/engine/devel/index.html

VTL
Seguici e condividi su:
onpost_follow  - icon Follow en US - API Gateway Mapping
Tweet  - en US Tweet - API Gateway Mapping
- en US save - API Gateway Mapping
Share  - en US share - API Gateway Mapping

Handlebars e Nodejs su AWS Lambda

Programming code on a monitor.  - coding - Handlebars e Nodejs su AWS Lambda

Helpers di Handlebars in Nodejs per template complessi

Mi sono ritrovato a dover creare delle pagine html statiche recuperando i dati da un database tramite la creazione di una funzione Lambda su AWS. La soluzione che mi è parsa subito la migliore è stata quella di scegliere di utilizzare la libreria https://handlebarsjs.com/ che permette la creazione di un template e la sostituzione all’interno di singoli riferimenti o di parti più complesse.

Non avendo mai utilizzato gli helpers di Handlebars, ho iniziato la ricerca online per trovare qualche suggerimento. Di seguito riporto i passaggi seguiti per l’utilizzo all’interno di una funzione Lambda, messi insieme sfruttando quanto trovato online e dopo alcuni ragionamenti personali.

Necessità:

  • scrivere una funziona async/wait che recuperato un template, sostituisca tutte le occorrenze e restituisca un html usabile per essere salvato in un file html su S3
  • utilizzare gli helpers per la sostituzione di occorrenze complesse, sia da dati statici (file json) sia da dati dinamici recuperati da database

Alla funzione, richiamata in modo asincrono, vengono passati i dati dinamici recuperati dal database. All’interno di un blocco try/catch richiama gli helpers e il template elabora i dati e restituisce un html pronto ad essere salvato su S3 per essere pubblicato online.

const document = fs.readFileSync('template-tpl.html', 'utf-8');
const menuJson = require("menu.json");
async function getHtmlPageContent(pack){
    try {
        require("hb-helpers.js")(handlebars, pack);
        const template = handlebars.compile(document);
        let data = {};
        data.itemsMenu = menuJson;
        const html = template(data);
        return html;
    } catch (error) {
        console.log('HBS ERROR', error);
        return context.fail(error);
    }
}

Fuori dalla funzione, in fase di impostazione, avevo dichiarato due costanti: la prima contenente il template html, la seconda contenente la struttura json del menù. Per prima cosa nella funzione, richiamo un file js esterno contenente gli helpers:

require("hb-helpers.js")(handlebars, pack);

e gli passo l’oggetto handlebars (oggetto della libreria) e i valori dinamici ottenuti dal database utilizzati nell’helpers per la gestione delle lingue. Quindi compilo il template html nella costante template e imposto la variabile itemsMenu dell’oggetto data con i valori del json per costruire il menu.

const template = handlebars.compile(document);
let data = {};
data.itemsMenu = menuJson;

A questo punto fondo l’oggetto data con il template per ottenere l’html completo che la funzione restituirà.

const html = template(data);
return html;

Successivamente analizziamo nel dettaglio alcuni particolari dei singoli file utilizzati.

Template HTML – (template-tpl.html)

<div class="navbar-collapse collapse float-right nav-main-collapse">
   <nav class="nav-main">
      <ul id="topMain" class="nav nav-pills nav-main">
          {{#each itemsMenu}}
              {{menuItem}}
          {{/each}}
      </ul>
  </nav>
</div>

Blocco html del menu contenente i tag di Handlebars per iterare sull’oggetto itemsMenu (variabile dell’oggetto data contenente il json), dove menuItem è l’oggetto che verrà utilizzato dall’helpers per la sostituzione con le singole voci di menu.

Helpers – (hb-helpers.js)

function hbsHelpers(hbs, pack) {
   //MENU
   hbs.registerHelper('menuItem', function() {
     var text    = hbs.escapeExpression(this.text),
         liClass = hbs.escapeExpression(this.liClass),
         href    = hbs.escapeExpression(this.url),
         aClass  = hbs.escapeExpression(this.aClass),
         spanClass  = hbs.escapeExpression(this.spanClass);
     return new hbs.SafeString(
       '<li class="'+liClass+'"><a href="'+href+'" class="'+aClass+'"><span class="trn '+spanClass+'">'+text+'</span></a></li>'
     );
   });
}
module.exports = hbsHelpers;

La funzione hbsHelpers con la registrazione dell’helpers menuItem. Questo helper recupera dal json (oggetto data.itemsMenu) i valori per text, liClass, href, aClass e spanClass e li utilizza per la costruzione della voce di menu.

Json del menu – (menu.json)

[
    {
        "text": "HOME",
        "icon": "",
        "liClass": "",
        "aClass": "",
        "spanClass": "theme-color",
        "url": "/index.html"
    },
    {
        "text": "TOUR",
        "icon": "",
        "liClass": "",
        "aClass": "",
        "spanClass": "theme-color",
        "url": "/tour.html"
    }
]

Un semplicissimo json contenente i valori per la costruzione del menu.

In conclusione, sfruttando le potenzialità di Handlebars e dei suoi helpers, è possibile costruire un html partendo da un template complesso.

Seguici e condividi su:
onpost_follow  - icon Follow en US - Handlebars e Nodejs su AWS Lambda
Tweet  - en US Tweet - Handlebars e Nodejs su AWS Lambda
- en US save - Handlebars e Nodejs su AWS Lambda
Share  - en US share - Handlebars e Nodejs su AWS Lambda

Condividere per migliorarsi

Mi sono trovato spesso ad avere difficoltà nel trovare una guida semplice e completa ad un problema riscontrato durante lo sviluppo di un sito o la configurazione di un servizio.

Vorrei, con questo mio blog, cercare di riportare in modo più semplice e completo possibile delle guide su argomenti che ho affrontato nella mia carriera di sviluppatore.

Credo fortemente che la condivisione di informazioni relative alla risoluzione di problemi pratici, sia molto importante per la crescita personale e per il confronto con chi come me affronta queste sfide tutti i giorni. Mi piacerebbe anche arricchire la documentazione disponibile in lingua italiana, attualmente piuttosto scarsa.

Seguici e condividi su:
onpost_follow  - icon Follow en US - Condividere per migliorarsi
Tweet  - en US Tweet - Condividere per migliorarsi
- en US save - Condividere per migliorarsi
Share  - en US share - Condividere per migliorarsi