Serverless Computing con AWS Lambda e API Gateway: Una Guida Completa

Lambda e API Gateway: una combinazione vincente per creare del codice serverless.
Introduzione
Immaginiamo di aver bisogno di scrivere una funzione che ci restituisca un risultato, magari in formato JSON, dopo aver eseguito qualche operazione.
Magari si tratta di una singola funzione -o anche solo un paio- e mettere su un’intera infrastruttura sembra assurdo: grazie alle funzioni Lambda, il problema può essere facilmente risolto.

Davvero?
Cos’è Lambda
Si tratta di un servizio AWS che permette di eseguire del codice serverless, ossia senza la necessità di avere a disposizione un server o di doverne effettuare il provisioning.
Il bello di Lambda è questo: organizzando il codice in singole funzioni sotto forma di richiesta = risultato, Lambda andrà ad eseguire la funzione solo quando è necessario ridimensionandosi automaticamente.
Le tariffe sono calcolate solo in base ai tempi di calcolo, perciò non viene addebitato alcun costo quando il codice non è in esecuzione, ma solo quando viene effettivamente utilizzato.
Qui risiede il concetto chiave: per pagare il meno possibile, queste funzioni devono essere efficienti al massimo. Sono supportati diversi linguaggi, tra cui Node.js e Python, motivo per cui possiamo scrivere il codice utilizzando lo strumento che più ci torna facile e poi crearne una funzione Lambda.
Come creare una funzione Lambda
Per creare una funzione è necessario prima di tutto accedere alla console di AWS e cercare tra i servizi “Lambda”: la schermata mostrata di seguito è il tipico scenario:

Elenco funzioni Lambda
Cliccando sul pulsante in alto a destra “Crea funzione”, si aprirà una schermata come la seguente: da qui, potremo creare la nostra funzione assegnandole un nome e scegliendo quale linguaggio andremo ad utilizzare.
Le possibilità sono diverse: Node.js, Ruby, Python, ma anche Go, Java e .NET Core. In questo caso di esempio, andremo ad utilizzare Python.
Una volta inserite le informazioni richieste nel form precedente, visualizzeremo una schermata come quella riportata nella prossima figura, dove avremo a disposizione un file chiamato lambda_functions.py che ci servirà per inserire il nostro codice.
Clicchiamo quindi sul file Python e vediamo che c’è già del codice: quello che ci viene mostrato nell’esempio, ci permette di restituire un JSON di risposta con codice HTTP pari a 200 e un body con messaggio tipico da funzioni “Hello world”.

Codice di esempio per un banale "Hello world"
In questo caso, ci interessa notare due cose: il tasto “Test” ci permette di verificare se, per esempio, nella nostra funzione ci sono errori di sintassi o di esecuzione.
Chiaramente, nel primo caso, sarebbe opportuno testare prima la funzione in locale e poi creare una Lambda, ma si tratta di una funzionalità molto utile, perché ci permette anche di definire degli “eventi”, ossia dei parametri in ingresso che ci permettono di rendere dinamica la funzione.
Questi eventi possono essere creati per testare più casi d’uso, utilizzando sempre il formato JSON, proprio come fosse il body di una request tradizionale:

Esempio di evento
La seconda cosa da notare è il badge in verde sulla destra dove si dice “Changed deployed”: ogni volta che modifichiamo la nostra funzione, gli aggiornamenti devono essere deployati per poter essere utilizzate.
Se clicchiamo sul tasto “Test”, questo è il risultato dell’esecuzione:

Test della funziona getHello
Oltre la response che viene visualizzata nel formato che abbiamo definito nel return della funzione, facciamo caso ai log: nell’ultima riga che afferisce al report, vengono indicati i tempi di elaborazione della funzione (1.74 ms), quanto effettivamente viene conteggiato dalla fatturazione AWS (2 ms), la dimensione della memoria e quella effettivamente utilizzata (il minimo è 128 MB).
Dobbiamo preoccuparci dei prezzi? Assolutamente no: qui è possibile trovare un riepilogo dei costi, ma basti sapere che il piano di utilizzo gratuito per AWS Lambda include 1 milione di richieste al mese e 400.000 GB/secondo di tempo di elaborazione al mese.
Anche ammettendo che facessimo oltre 30.000 richieste al giorno ogni giorno per un mese, non riusciremmo a superare la soglia. Non male, no?
Ok, ora che la nostra funzione è pronta, come possiamo utilizzarla dall’esterno? Ecco qui che viene in soccorso API Gateway.
Cos’è API Gateway
Questo servizio ci permette di gestire delle API mettendosi in mezzo tra un client e una raccolta di servizi back end. In questo caso, è possibile far sì che API Gateway si metta in mezzo tra la rete Internet e le nostre Lambda.

Esempio di funzionamento dell'API Gateway
Come funziona
Come fatto anche in precedenza, cerchiamo tra i servizi AWS quello relativo all’API Gateway e vedremo una schermata come la seguente:

Panoramica dell'API Gateway
Per creare un API, basta cliccare nel tasto in alto a destra e scegliere la tipologia da utilizzare. Un API REST può fare al caso nostro, soprattutto se poi volessimo rendere la funzione parametrizzabile:

Configurazione API Rest
Dopo aver cliccato su “Crea” e aver inserito le informazioni che vengono richieste nel modulo sottostante, come nome e il tipo di protocollo da utilizzare, proseguiamo e andiamo a creare tutto l’occorrente, come risorse e metodi.

Creazione di una nuova API

Riepilogo delle risorse presenti
Come prima cosa, creiamo una risorsa: questo farà sì che sia possibile accedere alla nostra API tramite degli endpoint specifici, come ad esempio getHelloWorld:

Creazione di una risorsa

Configurazione della risorsa
Una volta creata la risorsa, passiamo al metodo: ci basterà un semplice metodo GET che ci restituisca il messaggio e il codice HTTP visto prima durante il test della Lambda:

Creazione di nuovo metodo
In questa sezione, abbiamo la possibilità di scegliere se collegare la nostra API ad una funzione Lambda: iniziamo a scrivere il nome della funzione (nel nostro caso, era getHello) e clicchiamo su “Salva”:

Configurazione del metodo
Quello che ci verrà mostrato è lo schema di funzionamento della risorsa appena creata: quando all’API Gateway arriva una richiesta, questa invoca la funzione Lambda, gestisce la risposta e la include nella response della richiesta originale.

Schema della risorsa
Per testarla, possiamo cliccare sul pulsante “Test” e visualizzare la stessa risposta che avevamo ottenuto in precedenza.

Test del metodo
A questo punto, è ora di distribuire la nostra API: apriamo il menù “Operazioni”, clicchiamo su “Distribuisci”:

Distribuzione dell'API
In questa sezione, andremo a definire la cosiddetta “fase”, ossia la versione in cui si trova la nostra funzione. Possiamo definirla come alpha, beta o anche v1: la fase è qualcosa che serve agli sviluppatori per indicare a che punto è la lavorazione del codice.

Definizione della fase dell'API
Clicchiamo su “Distribuzione” e vediamo una pagina come la seguente, dove in alto viene riportato l’endpoint da chiamare per utilizzare la nostra API. Lo copiamo e passiamo a testarlo!

Panoramica della fase
Niente di più semplice: basterà aprire Postman (o un qualsiasi altro client), inserire l’URL mostrato nella schermata, aggiungere la risorsa che abbiamo creato (nel nostro caso, gethelloworld) e specificare come metodo della richiesta GET: questo è il risultato:

Esempio di utilizzo con Postman
L’esempio mostrato è molto, molto semplice, ma pensiamo a qualcosa che possa prendere in input dei parametri e restituirci un risultato, senza dover ricorrere ad un intero server che ne gestisca la scalabilità, la durabilità o la resilienza, minimizzando i costi: niente male, direi!
That’s all, folks!