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.

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.

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

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