{"id":322,"date":"2018-10-10T10:53:40","date_gmt":"2018-10-10T08:53:40","guid":{"rendered":"https:\/\/blog.besharp.it\/?p=322"},"modified":"2023-02-22T17:25:42","modified_gmt":"2023-02-22T16:25:42","slug":"go-serverless-pt3","status":"publish","type":"post","link":"https:\/\/blog.besharp.it\/it\/go-serverless-pt3\/","title":{"rendered":"Go Serverless! Parte 3: software event driven e trigger"},"content":{"rendered":"

Leggi la prima parte<\/a> | Leggi la seconda parte<\/a><\/p>\n

Questa \u00e8 la terza e ultima parte<\/strong> della serie di tre articoli su come costruire una piattaforma di file sharing completamente serverless. In questo articolo <\/span>presenteremo la soluzione software completa di codice<\/strong> sia per il front-end che per il back-end.<\/span><\/p>\n

Analizzeremo nel dettaglio l\u2019architettura software, le scelin qte di progettazione adottate e l\u2019utilizzo dei trigger lato AWS che permette alla soluzione di funzionare correttamente.<\/span><\/p>\n

Come anticipato nel primo articolo della serie<\/a><\/span>, ci occuperemo anche delle pipeline di Continuous Integration e Continuous Delivery<\/strong>, in modo da poter eseguire deploy ripetibili ed affidabili semplicemente effettuando un push sul repository.<\/span><\/p>\n

Nell\u2019articolo precedente<\/a> abbiamo creato a mano una infrastruttura analoga a quella che andremo a raffinare e definire. Di quegli elementi bisogner\u00e0 eliminare l\u2019API Gateway che abbiamo creato come test, in quanto il deploy delle risorse utilizzate dal back-end sar\u00e0 gestito dalla pipeline automatica.<\/span><\/p>\n

Per terminare il deploy della soluzione occorrer\u00e0:<\/span><\/p>\n

    \n
  1. Scaricare il sorgente del front-end e del back-end<\/strong><\/li>\n
  2. Configurare due repository di CodeCommit per entrambi<\/strong><\/li>\n
  3. Configurare le pipeline<\/strong><\/li>\n
  4. Fare un \u201cPush\u201d del codice sui repository per avviare il processo di deploy automatico<\/strong><\/li>\n<\/ol>\n

    Ecco i repository per clonare il codice sorgente:<\/span><\/p>\n

    Front-end: <\/span>https:\/\/github.com\/besharpsrl\/serverless-day-fe<\/span><\/a>
    \nBack-end: <\/span>
    https:\/\/github.com\/besharpsrl\/serverless-day-be<\/span><\/a><\/p>\n

    Cominciamo quindi presentando le soluzioni adottate nello sviluppo del software<\/span><\/p>\n

    Il front-end<\/span><\/h2>\n

    Una parte fondamentale dell\u2019applicazione \u00e8 rappresentata dal front-end, applicazione scritta in React.js<\/strong> che permette all\u2019utente di loggarsi in un\u2019area sicura, caricare, condividere e scaricare documenti. <\/span><\/p>\n

    Seguendo questa guida sar\u00e0 possibile integrare il front-end con il nostro back-end serverless in modo da permettere alle azioni compiute dall\u2019utente in interfaccia di riflettersi realmente su S3 e sulle tabelle di DynamoDB.<\/span><\/p>\n

    Per cominciare, possiamo clonare il codice sorgente<\/strong> dal repository oppure scaricare lo zip<\/strong>. La struttura del pacchetto deve rispecchiare quanto segue:<\/span><\/p>\n

    \"\"<\/p>\n

    Assicuriamoci di essere nella root di progetto di modo da poter lanciare i seguenti comandi:<\/span><\/p>\n

    npm install<\/span>\r\nnpm start<\/span><\/pre>\n

    Possiamo quindi procedere a configurare la libreria AWS Amplify<\/strong>. <\/span><\/p>\n

    Amplify \u00e8 una libreria consigliata da AWS che solleva il programmatore dalla gestione nel dettaglio di alcuni aspetti del ciclo di vita dell\u2019applicazione legati ad Amazon AWS, in particolare, nel nostro caso specifico, i servizi Cognito, S3 e API Gateway<\/strong>. <\/span><\/p>\n

    Per configurare correttamente il tutto abbiamo provveduto a creare un semplice custom component che ha la funzione di file di configurazione<\/strong>:<\/span><\/p>\n

    \"\"<\/p>\n

    Come si pu\u00f2 vedere, tutti i parametri di configurazione di Aws Amplify sono contenuti qui e vanno sostituiti con id<\/strong> e arn<\/strong> delle risorse create nell\u2019articolo precedente.<\/span><\/p>\n

    Una volta completata la configurazione ed installate tutte le dipendenze, possiamo avviare l’applicazione<\/strong> e visualizzare la seguente schermata di login:<\/span><\/p>\n

    \"\"<\/p>\n

    Se aggiungiamo manualmente degli utenti nella CognitoUserPool sar\u00e0 possibile effettuare login e visualizzare la schermata principale dell\u2019applicazione<\/strong>.<\/span><\/p>\n

    \"\"<\/p>\n

    Il codice fornito \u00e8 ampiamente commentato per facilitarne la comprensione. Una caratteristica notevole di React.js \u00e8 il meccanismo di auto reload<\/strong>. Durante lo sviluppo, ogni modifica al codice, allo stile css o alle librerie si riflette quasi immediatamente nella applicazione visualizzata nel browser.<\/span><\/p>\n

    Un\u2019altra nota particolare riguarda l\u2019approccio alla gestione del DOM<\/strong> da parte di React.js. In un front-end Javascript tradizionale, siamo noi ad occuparci direttamente della modifica del DOM. Con React.js, invece, questa operazione viene gestita interamente dal Framework<\/strong>.<\/span><\/p>\n

    Ogni componente di React.js \u00e8 assimilabile ad un oggetto Javascript complesso, il cui \u00a0contesto, rappresentato da <\/span>this<\/em>, <\/b>permette di accedere ad una chiave chiamata <\/span>state<\/em> che rappresenta lo stato del componente. Ogni variazione degli attributi del componente provoca un cambiamento nel metodo <\/span>render<\/em>. Questo significa che la manipolazione diretta del DOM non \u00e8 pi\u00f9 necessaria ed \u00e8 gestita direttamente dal framework alla modifica dello <\/span>state<\/em>.<\/span><\/p>\n

    A tal proposito, si pu\u00f2 vedere nel componente Table.js come tale sistema permetta di visualizzare dei modali che altrimenti non sarebbero gestibili con i metodi tradizionali.<\/span><\/p>\n

    Back-end<\/span><\/h2>\n

    La parte di back-end applicativa viene servita mediante API Gateway e Lambda<\/strong>.<\/span><\/p>\n

    Entrambe queste risorse possono richiedere modifiche ad ogni deploy (in base alle modifiche effettuate al sorgente e alla struttura del back-end), per questa ragione abbiamo adottato una scelta che ci permette di ottenere in modo semplice ed efficace una gestione automatizzata dello stack AWS.<\/span><\/p>\n

    La scelta riguarda il framework impiegato, che \u00e8 ricaduta su Chalice<\/strong>: <\/span>https:\/\/github.com\/aws\/chalice<\/span><\/a>. Si tratta di un framework Python progettato per AWS<\/strong>, che incorpora un router simile a quello di Flask e un sistema di decorator che implementa le integrazioni con i servizi AWS supportati.<\/span><\/p>\n

    Mediante semplici dichiarazioni possiamo aggiungere al nostro back-end trigger AWS<\/strong>, per invocare metodi in risposta a determinati eventi, oppure configurare in modo gestito integrazioni complesse come quella di CognitoUserPool e degli authorizer di API Gateway.<\/span><\/p>\n

    All\u2019interno del repository troverete la soluzione completa con tutto il codice<\/strong>, i file di configurazione e quelli di utility. Non \u00e8 necessario preparare environment o installare dipendenze perch\u00e8 abbiamo incluso Dockerfile e docker-compose per rendere l\u2019avvio dell\u2019applicazione automatico. <\/span><\/p>\n

    Per avviare l\u2019applicazione usando Docker basta entrare nella root della soluzione e invocare<\/span><\/p>\n

    docker-compose up<\/span><\/pre>\n

    Nel caso si preferisca invece evitare docker e installare le dipendenze nel proprio sistema, occorre installare python 3.6, pip e successivamente tutte le dipendenze contenute in requirements.txt. Consigliamo vivamente di utilizzare un VirtualEnv dedicato nel caso in cui Docker non sia un\u2019opzione praticabile. <\/span><\/p>\n

    pip3 install -r requirements.txt --user<\/span><\/pre>\n

    Di seguito la struttura del progetto:<\/span><\/p>\n

    \"\"<\/p>\n

    Da notare la presenza della cartella chalicelib, che \u00e8 utilizzata per aggiungere classi custom al progetto in un modo riconosciuto dal framework. Salvare i moduli custom all\u2019interno di questa cartella serve a sfruttare la funzione di Chalice in grado di generare automaticamente \u00a0un pacchetto pronto per il deploy su AWS Lambda<\/strong>.<\/span><\/p>\n

    Come per il front-end, \u00e8 presente un file config.py per configurare tutti i parametri dipendenti dall\u2019account AWS che l\u2019applicazione e Chalice hanno bisogno di conoscere.<\/span><\/p>\n

    Abbiamo diviso i moduli in servizi, controller e connector; questa distinzione \u00e8 utile per mantenere ordine e favorire il riutilizzo del codice. Mediante questa organizzazione \u00e8 possibile mantenere DRY il codice di app.py, che contiene di fatto tutte le rotte del back-end opportunamente decorate. Tutta la logica applicativa, al netto delle rotte e della gestione dell\u2019output, si trova nei controller e nei servizi.<\/span><\/p>\n

    L\u2019intera interfaccia di comunicazione con il database \u00e8 stata implementata in un modulo separato (un connector), cos\u00ec da essere pi\u00f9 facilmente modificabile, ottimizzabile e sostituibile.<\/span><\/p>\n

    Chalice \u00e8 in grado provvedere al deploy e alla configurazione di API Gateway e Lambda; le configurazioni sono espresse in modo idiomatico nel codice applicativo.<\/span><\/p>\n

    Una volta pronto il progetto si pu\u00f2 effettuare il deploy automatico semplicemente invocando<\/span><\/p>\n

    chalice deploy<\/span><\/pre>\n

    Passiamo quindi ad analizzare la parte pi\u00f9 interessante del progetto, ovvero i decorator<\/strong> che permettono di integrare in modo semplice i servizi di AWS usando trigger e configurazioni di API Gateway.<\/span><\/p>\n

    L\u2019intera definizione delle rotte e dei trigger avviene in app.py, il file principale del back-end. Scorrendo il codice, \u00e8 possibile notare un gran numero di decorator. Questi sono il meccanismo utilizzato dal framework per dichiarare le rotte e le integrazioni con AWS. Nel progetto abbiamo utilizzato tre decorator: @app.route, @app.on_s3_event, @app.schedule.<\/strong><\/span><\/p>\n

    @app.route<\/span><\/h3>\n

    Chalice effettua il deploy di buona parte del back-end (eccetto metodi di reazione ad eventi, come vedremo in seguito) in una sola funzione Lambda. Il framework include un router, che si occupa di invocare il metodo corretto ad ogni invocazione. Questo decorator si rivolge al router: indica di creare e gestire una rotta su API Gateway che risponde ad uno o pi\u00f9 verbi HTTP. Il metodo che viene cos\u00ec \u201cdecorato\u201d \u00e8 quindi invocato dal router alle richieste che corrispondono alla rotta specificata.<\/span><\/p>\n

    Oltre a definire la rotta, il decorator accetta un numero di parametri per sfruttare al meglio l\u2019integrazione con API Gateway. Ad esempio, \u00e8 possibile configurare i settaggi per le CORS o l\u2019integrazione con una CognitoUserPool per l\u2019autenticazione delle API.<\/span><\/p>\n

    Esempio della definizione di un metodo autenticato, con settaggi CORS e un authorizer:<\/span><\/p>\n

    @app.route('\/test, methods=['GET'], authorizer=authorizer, <\/span>\r\ncors=CORS_CONFIG)<\/span>\r\ndef mymethod():<\/span>\r\n\u00a0 \u00a0 \u00a0 return {\u201cmessage\u201d: \u201cok\u201d}<\/span><\/pre>\n

    @app.on_s3_event<\/span><\/h3>\n

    In modo simile al decorator utilizzato per le rotte, \u00e8 possibile indicare al framework che un determinato metodo deve essere invocato quando si verifica un evento su S3.<\/span><\/p>\n

    Nel nostro progetto sfruttiamo questo trigger per reagire e trasformare i file caricati dagli utenti. Il decorator prende in input il tipo di evento di interesse e il bucket di riferimento.<\/span><\/p>\n

    Esempio:<\/span><\/p>\n

    @app.on_s3_event(bucket=config.S3_UPLOADS_BUCKET_NAME, \r\nevents=['s3:ObjectCreated:*'])<\/span>\r\ndef react_to_s3_upload(event):<\/span>\r\n     \u2026<\/span><\/pre>\n

    Dietro le quinte, questo provoca il deploy di una Lambda separata da quella principale, che ha come trigger il caricamento di un file su S3 e che viene invocata automaticamente da AWS ad ogni evento <\/span><\/p>\n

    s3:ObjectCreated:* <\/span><\/pre>\n

    sul bucket specificato.<\/span><\/p>\n

    @app.schedule<\/span><\/h3>\n

    Come \u00e8 facile intuire dal nome, questo decorator indica di eseguire il metodo ad intervalli regolari o comunque secondo uno scheduler.<\/span><\/p>\n

    Crea e gestisce una regola su CloudWatch events per avviare una Lambda dedicata con il metodo da eseguire.<\/span><\/p>\n

    @app.schedule(Rate(5, unit=Rate.MINUTES))<\/span>\r\ndef expire_files(event):<\/span><\/pre>\n

     <\/p>\n

    Pipeline di CD\/CI<\/span><\/h2>\n

    Sebbene sia possibile caricare il Front-End compilato sul bucket s3 preparato nei precedenti articoli, ed eseguire un chalice deploy per avere tutto correttamente configurato, vogliamo completare l\u2019architettura accennando alle pipeline automatiche per il deploy del codice<\/strong>.<\/span><\/p>\n

    Abbiamo gi\u00e0 parlato di CD\/CI in questo articolo<\/a>.<\/span><\/span><\/p>\n

    Questa volta la soluzione sar\u00e0 leggermente diversa.<\/span><\/p>\n

    Come prima cosa occorre creare due nuove applicazioni su CodeBuild, una per il front-end ed una per il back-end. Occorre configurare CodeBuild per utilizzare il file buildspec.yml presente nella root del repository.<\/span><\/p>\n

     <\/p>\n

    Il CodeBuild di front-end pu\u00f2 utilizzare un\u2019immagine standard di nodejs, e quello del back-end una con Python3.6.<\/span><\/p>\n

    \"\"<\/p>\n

    \"\"<\/p>\n

    In ognuno dei repositories sono presenti i file buildspec.yml. Questi file definiscono i passi eseguiti da CodeBuild per produrre il pacchetto di cui effettuare il deploy ed anche le istruzioni di deploy stesse.<\/span><\/p>\n

    Una volta create le applicazioni su CodeBuild, basta creare altrettante Pipeline che facciano il source da CodeCommit e poi passino il codice al corrispondente CodeBuild. In nessuna delle due pipeline occorre specificare lo stadio di deploy, perch\u00e8 per questo esempio abbiamo incluso le istruzioni nel buildspec.yml in modo che siano eseguite dopo il processo di build.<\/span><\/p>\n

    Di conseguenza, gli IAM role associati ai CodeBuild devono avere il permesso di caricare ed eliminare file da S3, gestire API Gateway e Lambda, e invalidare la distribuzione di CloudFront.<\/span><\/p>\n

    Analizzando i buildspec possiamo osservare le operazioni eseguite per il build e deploy delle applicazioni.<\/span><\/p>\n

    Cominciando dal Front-End che esegue i seguenti passi<\/span><\/p>\n

    - npm install<\/span>\r\n- npm run build<\/span>\r\n- cd .\/build && aws s3 sync --delete . s3:\/\/$S3_BUCKET_NAME\/<\/span>\r\n- aws cloudfront create-invalidation --distribution-id $DISTRIBUTION_ID --paths \"\/*\"<\/span><\/pre>\n

     <\/p>\n

    In ordine: <\/span><\/p>\n

      \n
    1. Installare le dipendenze<\/span><\/li>\n
    2. Creare il pacchetto di React.js<\/span><\/li>\n
    3. Sincronizzare l\u2019output della build con il bucket s3 del front-end (ovvero aggiornare i file presenti, aggiungere quelli nuovi ed eliminare quelli non pi\u00f9 presenti)<\/span><\/li>\n
    4. Invalidare il contenuto della distribuzione CloudFront per rendere effettive le modifiche.<\/span><\/li>\n<\/ol>\n

      I passi eseguiti dal back-end invece sono molto diversi<\/span><\/p>\n

       \u00a0\u00a0 - rm -rf mydoctransfer-lambda\/.chalice\/deployed<\/span>\r\n \u00a0\u00a0\u00a0- mkdir mydoctransfer-lambda\/.chalice\/deployed<\/span>\r\n \u00a0\u00a0\u00a0- cd mydoctransfer-lambda\/.chalice\/deployed && aws s3 sync --delete s3:\/\/$RELEASES_S3_BUCKET\/backend\/chalice .<\/span>\r\n \u00a0\u00a0\u00a0- cd mydoctransfer-lambda && pip3.6 install -r requirements.txt --user<\/span>\r\n \u00a0\u00a0\u00a0- aws s3 cp s3:\/\/$CONFIG_S3_BUCKET\/backend\/$ENV\/modsam.py .<\/span>\r\n \u00a0\u00a0\u00a0- cd mydoctransfer-lambda\/.chalice && aws s3 cp s3:\/\/$CONFIG_S3_BUCKET\/backend\/$ENV\/config.json .<\/span>\r\n \u00a0\u00a0\u00a0- .\/build.sh<\/span>\r\n \u00a0\u00a0\u00a0- cd mydoctransfer-lambda\/.chalice\/deployed && aws s3 sync --delete . s3:\/\/$RELEASES_S3_BUCKET\/backend\/chalice<\/span><\/pre>\n

      Il cuore del processo \u00e8 build.sh, che contiene solo una minima configurazione della shell e il comando chalice deploy.<\/span><\/p>\n

      I restanti passi servono a preparare l\u2019ambiente locale. Oltre ad installare le dipendenze provvedono anche a persistere, mediante un bucket S3 di appoggio, lo stato dei deploy memorizzato in \/.chalice\/deployed.<\/span><\/p>\n

      A questo punto basta effettuare push sulle pipeline per effettuare deploy automatici di front-end e back-end ed avere finalmente pronta un’applicazione di file sharing completamente serverless.<\/span><\/p>\n

      Enjoy \ud83d\ude42<\/span><\/p>\n

      Leggi la prima parte<\/a> | Leggi la seconda parte<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"

      Leggi la prima parte | Leggi la seconda parte Questa \u00e8 la terza e ultima parte della serie di tre […]<\/p>\n","protected":false},"author":6,"featured_media":363,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[477],"tags":[263,364,360,271,267],"yoast_head":"\nGo Serverless! Parte 3: software event driven e trigger - Proud2beCloud Blog<\/title>\n<meta name=\"description\" content=\"Go Serverless! Parte 3: la soluzione software completa di codice sia per il front-end che per il back-end.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/blog.besharp.it\/it\/go-serverless-pt3\/\" \/>\n<meta property=\"og:locale\" content=\"it_IT\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Go Serverless! Parte 3: software event driven e trigger\" \/>\n<meta property=\"og:description\" content=\"Go Serverless! Parte 3: la soluzione software completa di codice sia per il front-end che per il back-end.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/blog.besharp.it\/it\/go-serverless-pt3\/\" \/>\n<meta property=\"og:site_name\" content=\"Proud2beCloud Blog\" \/>\n<meta property=\"article:published_time\" content=\"2018-10-10T08:53:40+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2023-02-22T16:25:42+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/blog.besharp.it\/wp-content\/uploads\/2018\/10\/SERVERLESS-03.png\" \/>\n\t<meta property=\"og:image:width\" content=\"4268\" \/>\n\t<meta property=\"og:image:height\" content=\"3200\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Alessandro Gaggia\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:title\" content=\"Go Serverless! Parte 3: software event driven e trigger\" \/>\n<meta name=\"twitter:description\" content=\"Go Serverless! Parte 3: la soluzione software completa di codice sia per il front-end che per il back-end.\" \/>\n<meta name=\"twitter:image\" content=\"https:\/\/blog.besharp.it\/wp-content\/uploads\/2018\/10\/SERVERLESS-03.png\" \/>\n<meta name=\"twitter:label1\" content=\"Scritto da\" \/>\n\t<meta name=\"twitter:data1\" content=\"Alessandro Gaggia\" \/>\n\t<meta name=\"twitter:label2\" content=\"Tempo di lettura stimato\" \/>\n\t<meta name=\"twitter:data2\" content=\"10 minuti\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/blog.besharp.it\/it\/go-serverless-pt3\/\",\"url\":\"https:\/\/blog.besharp.it\/it\/go-serverless-pt3\/\",\"name\":\"Go Serverless! Parte 3: software event driven e trigger - Proud2beCloud Blog\",\"isPartOf\":{\"@id\":\"https:\/\/blog.besharp.it\/it\/#website\"},\"datePublished\":\"2018-10-10T08:53:40+00:00\",\"dateModified\":\"2023-02-22T16:25:42+00:00\",\"author\":{\"@id\":\"https:\/\/blog.besharp.it\/it\/#\/schema\/person\/f27fc12d10867c6ea6e0158ce4dd8924\"},\"description\":\"Go Serverless! Parte 3: la soluzione software completa di codice sia per il front-end che per il back-end.\",\"breadcrumb\":{\"@id\":\"https:\/\/blog.besharp.it\/it\/go-serverless-pt3\/#breadcrumb\"},\"inLanguage\":\"it-IT\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/blog.besharp.it\/it\/go-serverless-pt3\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/blog.besharp.it\/it\/go-serverless-pt3\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/blog.besharp.it\/it\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Go Serverless! Parte 3: software event driven e trigger\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/blog.besharp.it\/it\/#website\",\"url\":\"https:\/\/blog.besharp.it\/it\/\",\"name\":\"Proud2beCloud Blog\",\"description\":\"il blog di beSharp\",\"alternateName\":\"Proud2beCloud Blog\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/blog.besharp.it\/it\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"it-IT\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/blog.besharp.it\/it\/#\/schema\/person\/f27fc12d10867c6ea6e0158ce4dd8924\",\"name\":\"Alessandro Gaggia\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"it-IT\",\"@id\":\"https:\/\/blog.besharp.it\/it\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/f58dc28050f26409e22ab60346d06220?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/f58dc28050f26409e22ab60346d06220?s=96&d=mm&r=g\",\"caption\":\"Alessandro Gaggia\"},\"description\":\"Head of software development di beSharp, Full-Stack developer, mi occupo di garantire lo stato dell\u2019arte di tutta la nostra codebase. Scrivo codice in quasi ogni linguaggio, ma prediligo Typescript. Respiro Informatica, Game design, Cinema, Fumetti e buona cucina. Disegno per passione!\",\"url\":\"https:\/\/blog.besharp.it\/it\/author\/alessandro-gaggia\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Go Serverless! Parte 3: software event driven e trigger - Proud2beCloud Blog","description":"Go Serverless! Parte 3: la soluzione software completa di codice sia per il front-end che per il back-end.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/blog.besharp.it\/it\/go-serverless-pt3\/","og_locale":"it_IT","og_type":"article","og_title":"Go Serverless! Parte 3: software event driven e trigger","og_description":"Go Serverless! Parte 3: la soluzione software completa di codice sia per il front-end che per il back-end.","og_url":"https:\/\/blog.besharp.it\/it\/go-serverless-pt3\/","og_site_name":"Proud2beCloud Blog","article_published_time":"2018-10-10T08:53:40+00:00","article_modified_time":"2023-02-22T16:25:42+00:00","og_image":[{"width":4268,"height":3200,"url":"https:\/\/blog.besharp.it\/wp-content\/uploads\/2018\/10\/SERVERLESS-03.png","type":"image\/png"}],"author":"Alessandro Gaggia","twitter_card":"summary_large_image","twitter_title":"Go Serverless! Parte 3: software event driven e trigger","twitter_description":"Go Serverless! Parte 3: la soluzione software completa di codice sia per il front-end che per il back-end.","twitter_image":"https:\/\/blog.besharp.it\/wp-content\/uploads\/2018\/10\/SERVERLESS-03.png","twitter_misc":{"Scritto da":"Alessandro Gaggia","Tempo di lettura stimato":"10 minuti"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/blog.besharp.it\/it\/go-serverless-pt3\/","url":"https:\/\/blog.besharp.it\/it\/go-serverless-pt3\/","name":"Go Serverless! Parte 3: software event driven e trigger - Proud2beCloud Blog","isPartOf":{"@id":"https:\/\/blog.besharp.it\/it\/#website"},"datePublished":"2018-10-10T08:53:40+00:00","dateModified":"2023-02-22T16:25:42+00:00","author":{"@id":"https:\/\/blog.besharp.it\/it\/#\/schema\/person\/f27fc12d10867c6ea6e0158ce4dd8924"},"description":"Go Serverless! Parte 3: la soluzione software completa di codice sia per il front-end che per il back-end.","breadcrumb":{"@id":"https:\/\/blog.besharp.it\/it\/go-serverless-pt3\/#breadcrumb"},"inLanguage":"it-IT","potentialAction":[{"@type":"ReadAction","target":["https:\/\/blog.besharp.it\/it\/go-serverless-pt3\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/blog.besharp.it\/it\/go-serverless-pt3\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/blog.besharp.it\/it\/"},{"@type":"ListItem","position":2,"name":"Go Serverless! Parte 3: software event driven e trigger"}]},{"@type":"WebSite","@id":"https:\/\/blog.besharp.it\/it\/#website","url":"https:\/\/blog.besharp.it\/it\/","name":"Proud2beCloud Blog","description":"il blog di beSharp","alternateName":"Proud2beCloud Blog","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/blog.besharp.it\/it\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"it-IT"},{"@type":"Person","@id":"https:\/\/blog.besharp.it\/it\/#\/schema\/person\/f27fc12d10867c6ea6e0158ce4dd8924","name":"Alessandro Gaggia","image":{"@type":"ImageObject","inLanguage":"it-IT","@id":"https:\/\/blog.besharp.it\/it\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/f58dc28050f26409e22ab60346d06220?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/f58dc28050f26409e22ab60346d06220?s=96&d=mm&r=g","caption":"Alessandro Gaggia"},"description":"Head of software development di beSharp, Full-Stack developer, mi occupo di garantire lo stato dell\u2019arte di tutta la nostra codebase. Scrivo codice in quasi ogni linguaggio, ma prediligo Typescript. Respiro Informatica, Game design, Cinema, Fumetti e buona cucina. Disegno per passione!","url":"https:\/\/blog.besharp.it\/it\/author\/alessandro-gaggia\/"}]}},"_links":{"self":[{"href":"https:\/\/blog.besharp.it\/it\/wp-json\/wp\/v2\/posts\/322"}],"collection":[{"href":"https:\/\/blog.besharp.it\/it\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.besharp.it\/it\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.besharp.it\/it\/wp-json\/wp\/v2\/users\/6"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.besharp.it\/it\/wp-json\/wp\/v2\/comments?post=322"}],"version-history":[{"count":0,"href":"https:\/\/blog.besharp.it\/it\/wp-json\/wp\/v2\/posts\/322\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.besharp.it\/it\/wp-json\/wp\/v2\/media\/363"}],"wp:attachment":[{"href":"https:\/\/blog.besharp.it\/it\/wp-json\/wp\/v2\/media?parent=322"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.besharp.it\/it\/wp-json\/wp\/v2\/categories?post=322"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.besharp.it\/it\/wp-json\/wp\/v2\/tags?post=322"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}