Dopo tanti anni che faccio questo lavoro, non ricordo quante volte mi sono trovato al cospetto di API mal documentate, scritte male o che non rispettassero nessuno standard o pattern, tanto da rendere l’integrazione un bagno di sangue. Se 10 anni fa ognuno aveva la sua idea di implementazione e forse poteva essere anche tollerato, oggi con tutti gli strumenti e gli standard a disposizione, questo non è più concepibile.
Se volete quindi risolvere una volta per tutte i problemi di incomprensibilità delle vostre API, o se solo volete trovare conferma sulla bontà del vostro lavoro, continuate la lettura di questo articolo, e troverete le risposte a tutte le vostre domande per creare API RESTful ben documentate e senza pesare sul tempo di realizzazione.
RESTful non è un termine nuovo. Si riferisce a uno stile architetturale in cui servizi Web ricevono e inviano dati da e verso le applicazioni client e con l’obiettivo di centralizzare i dati che verranno utilizzati.
La scelta degli strumenti giusti per scrivere i servizi RESTful è fondamentale poiché dobbiamo preoccuparci di scalabilità, manutenzione, documentazione e tutti gli altri aspetti rilevanti. ASP.NET Core ci offre un’API potente e facile da usare, ottima per raggiungere questi obiettivi.
In questo articolo mostrerò come scrivere un’applicazione API RESTful ben strutturata per uno scenario “quasi” reale, usando il framework ASP.NET Core. Cercherò anche di dettagliare modelli e strategie comuni per semplificare il processo di sviluppo, alcuni pattern e l’architettura utilizzata. Mostrerò anche come integrare framework e librerie, come Dependency injection, AutoMapper , NLog per fornire le funzionalità necessarie.
Sicuramente vi sarà capitato di leggere qualche articolo di cucina, di come si preparano squisiti dolci o primi piatti; la prima cosa è la lista degli ingredienti. Anche nel nostro caso abbiamo bisogno di alcuni “ingredienti” per poter realizzare il nostro “dolce”!
Per intraprendere questo percorso per cominciare è necessario avere una buona conoscenza dei concetti di programmazione orientata agli oggetti.
Andiamo avanti poi col supporre di sapere cos’è REST, come funziona il protocollo HTTP, cosa sono gli endpoint API e cos’è un JSON (esistono in rete ottimo tutorial introduttivo su questo argomento).
Un altro requisito necessario è avere una conoscenza di base dei database NoSQL e del loro funzionamento, in particolare mongodb, che sarà quello che utilizzeremo nella nostra applicazione. Giusto come introduzione generale, possiamo dire che i database NoSQL sono appositamente realizzati per modelli di dati specifici e hanno schemi flessibili per creare applicazioni moderne. I database NoSQL si sono affermati per la facilità di sviluppo, la funzionalità e la scalabilità delle prestazioni.
Infine è necessario una conoscenza di base di docker, e docker-compose, che anche se non necessario per eseguire l’applicazione, sarà comunque utile conoscere nel caso volessimo rilasciare la nostra applicazione in un container.
ASP.NET Core è il progetto Microsoft per eseguire applicazione dotnet in sistemi operativi differenti oltre a Microsoft Windows. Sono in tutto quattro le caratteristiche distintive della nuova tecnologia:
Non è la prima volta che Microsoft si approccia all’universo dell’open source, ma è indubbiamente la prima volta che lo fa per una tecnologia di tale portata, rendendo pubblici i codici sorgente delle librerie di supporto alle applicazioni. Un altro grande passo avanti è l’orientamento al cloud ed al versante multi-piattaforma, non presente invece in NET Framework.
La scelta di utilizzare container docker si sposa perfettamente con la scelta tecnologica fatta, infatti le applicazioni ASP.NET Core possono essere eseguite su container linux, così come su windows e macosx.
I container saranno tutti creati a partire da un’immagine unix di base (alpine), con sopra il framework ASP.NET Core.
L’applicazione che andremo a creare, seppur semplice, avrà una struttura estensibile e potrà essere presa come riferimento per applicazioni più complesse.
Una domanda legittima che adesso può venire spontanea è: perchè RESTful? bene, il motivo è presto detto: scalabilità.
Per scalabilità non si intende sempre e solo un problema di server o infrastrutture, ma anche un problema squisitamente software.
Prendiamo per esempio i colossi del web, come Google, Facebook, Twitter o Linkedin, la loro popolarità e importanza sul mercato è sicuramente frutto di duro lavoro interno, ma è anche frutto del fatto che hanno messo a disposizione i loro servizi tramite un set di API ben documentate. Questi grandi BIG quindi usano REST per fare scalare il loro utilizzo anche verso sistemi di terze parti, come client web, applicazioni mobile, ecc…
Questo per dire, che se facciamo bene il nostro lavoro, e forniamo ottimi servizi e ben documentati, in tanti potranno utilizzarli, permettendoci di crescere velocemente.
Esistono delle linee guida e regole da seguire quando si progettano delle API in modo che siano logicamente comprensibili anche da chi non le ha sviluppate. In questo articolo quindi cercherò anche di fornire un insieme di linee guida attraverso punti chiave / suggerimenti su come progettare API.
La documentazione dei servizi esposti è molto importante, ed è per questo che adotteremo SWAGGER, un tool di sviluppo riconosciuto come standard dalla community per la produzione di documentazione di API.
Riporto di seguito le indicazione di base per la stesura di API RESTful:
Perchè utilizzare i metodi e i codici del Protocollo HTTP?
La risposta è semplice: cerchiamo di rendere più standard possibile la nostra applicazione, così che chiunque dovrà utilizzarla non dovrà studiarsi nulla di nuovo, ma troverà le cose esattamente dove se le aspetta e nel modo in cui se le aspetta.
In particolare:
Utilizziamo i metodi HTTP per le attività di modifica delle risorse (CRUD)
Utilizziamo i codici di risposta HTTP per la risposta al client, così che ogni client possa interpretare correttamente l’esito della chiamata fatta:
Lo scopo di questo articolo è illustrare in maniera semplice e chiara come strutturare un’applicazione RestFUL con ASP.NET Core ed eseguita su container docker, attraverso una architettura a servizi, avvalendosi di alcuni pattern di sviluppo e di alcune librerie disponibili su ASP.NET Core che ci semplificheranno la vita!
L’architettura dell’applicazione finale avrà una struttura come in figura:
Una architettura a servizi è una architettura dove la logica di business (BLL business logic layer) e la logica di accesso al db (DAL data access layer) coesistono insieme nella stessa applicazione e perciò “girano” nello stesso applicativo ( o container).
Generalmente la BLL è costituita come una libreria che contiene tutti i modelli e i servizi per la logica applicativa, mentre il DAL contiene le entità che mappano il db e la logica di accesso ai dati. Vedamo nel dettaglio queste due parti fondamentali dell’applicazione.
In questa parte dell’applicazione risiede gran parte del codice che andiamo a scrivere, perché è qui che è inserita tutta la logica applicativa.
La struttura di tale layer può differire tra progetto e progetto, ma per una questione di organizzazione, di pratica, di abitudine, di pattern, o solo per giudizio, è sempre importante suddividere tale logica in varie cartelle, le collezioni di nomi di entità (o namespace).
I servizi sono le classi che contengono la logica, o in altre parole, il codice che scriveremo. I servizi verranno resi disponibili in tutte le parti dell’applicazione dove saranno necessari, attraverso la dependency injection.
Ogni applicazione API Restful necessita di almeno un controller per poter funzionare: il controller è il componente al quale arrivano tutte le chiamate dal frontend (l’utente), e si preoccupa di richiamare i servizi necessari a soddisfare le richieste, ritornando poi al frontend il risultato.
Il Data access layer (in italiano livello di accesso ai dati), è il livello applicativo che si preoccupa di accedere ai dati, quindi è il layer che comunica direttamente con la base dati.
All’interno del DAL è possibile trovare un ulteriore elemento architetturale, i repository, che sono le classi che implementano l’accesso al dato, specifico per ogni tipo di base dati. Nel nostro caso, l’implementazione del repository sarà verso il database mongodb, attraverso l’utilizzo di MongoClient, una libreria disponibile per il download su nuget.
ASP.NET Core supporta il modello progettuale software per l’inserimento delle dipendenze, ovvero una tecnica per ottenere l’inversione del controllo (IoC) tra classi e relative dipendenze.
Una dipendenza è qualsiasi oggetto richiesto da un altro oggetto.
L’idea alla base della Dependency Injection è quella di avere un componente esterno (assembler) che si occupi della creazione degli oggetti e delle loro relative dipendenze e di assemblarle mediante l’utilizzo dell’injection.
ASP.NET Core mette a disposizione dei metodi per poter aggiungere i servizi necessari ad un contenitore, e poi si prenderà lui carico di iniettare le dipendenze necessarie quando richieste.
Sarà quindi possibile aggiungere i servizi necessari per l’applicazione al container, e definire l’ambito della durata dei servizi (Temporaneo, con ambito o per richiesta o singleton).
La nostra applicazione utilizza un design pattern basata su tre elementi principali:
I DTO e i BO sono utilizzati per trasferire dati tra layer in una architettura applicativa multistrato e distribuita.
Il DTO è il modello atto a trasferire i dati dal layer dove è contenuta la logica di business (BLL) verso il layer di presentazione (frontend), quindi serve per presentare i dati. Non ha logiche al suo interno, ed è mappato partendo dall’entità di base.
Il BO è il modello che invece trasferisce i dati dal frontend (l’utente) verso il layer di accesso ai dati (DAL) passando attraverso la BLL, e dovrà quindi essere rimappato sull’entità. Può contenere logiche di conversione o elaborazione dei dati.
Per fare questi mapping (da Entità a DTO o da BO a Entità ad esempio) in maniera semplice e automatica, invece di procedere manualmente, è possibile utilizzare una libreria, Automapper, disponibile su nuget,
Automapper si basa su naming convention, ossia si basa sui nomi (e sul tipo) delle proprietà per mapparle da un oggetto su un altro.
I mapping possono comunque essere customizzati, quando ad esempio le proprietà hanno nomi o tipi differenti (es. una stringa in un enum).
I log sono un elemento fondamentale per ogni applicazione. Esistono moltissimi sistemi e metodi per collezionare i log, ma prima di ogni cosa, è necessario scriverli!
Nella nostra applicazione utilizzeremo una libreria, sempre disponibile su nuget, che si chiama NLog.
Per poter utilizzare la nostra applicazione, dobbiamo fornire un sistema di autenticazione, così che solo gli utenti abilitati possano accedere e sia possibile per noi profilare le chiamate per ogni utente. Questo è possibile attraverso una autenticazione su un servizio di authority che ci permette di utilizzare un token (un gettone) che identifica l’utente. L’aggiunta del token all’header delle chiamate permetterà cosi di profilare le richieste in arrivo dal frontend. Tutto questo si basa su un protocollo standard, OAuth2(https://oauth.net/2/). Non approfondiremo l’argomento, ma ci sono moltissime risorse online per chi avesse bisogno di studiare tale flusso di autenticazione.
Per la gestione dell’autenticazione faremo puntare la nostra applicazione ad un servizio esterno oline: https://auth0.com/ (Auth0 è un servizio che mette a disposizione un sistema di autenticazione già fatto, personalizzabile tramite impostazioni o tramite script javascript)
Docker è un progetto open source nato con lo scopo di automatizzare la distribuzione di applicazioni sotto forma di “contenitori” leggeri, portabili ed autosufficienti che possono essere eseguiti su cloud (pubblici o privati) o in locale.
I “contenitori” di Docker (chiamati con il termine inglese Container), sono quindi l’insieme dei dati di cui necessita un’applicazione per essere eseguita: librerie, altri eseguibili, rami del file system, file di configurazione, script, ecc.
Non è scopo di questo articolo approfondire il funzionamento di docker, quindi si rimanda al lettore eventuali necessari approfondimenti, in rete è disponibile tantissimo materiale sull’argomento.
Quello che ci interessa sapere, è che la nostra applicazione sarà contenuta e eseguita all’interno di questi container.
Per fare funzionare quindi il tutto è necessario scaricare ed installare docker desktop sul proprio PC, reperibile all’indirizzo:
Una considerazione aggiuntiva va fatta riguardo a docker-compose.
Compose è uno strumento per la definizione e l’esecuzione di applicazioni Docker multi-contenitore. In altre parole, se la tua applicazione è costituita da più container, è possibile utilizzare un file (docker-compose.yml) di configurazione con cui definire l’architettura della rete e tutti i servizi da eseguire.
L’uso di docker-compose è fondamentalmente un processo in tre fasi:
Quindi, ricapitolando, avremo:
Siamo così giunti alla fine di questo articolo, contenente spunti e suggerimenti utili per poter creare un’applicazione API RESTful con ASP.NET Core e docker, e nel prossimo articolo andremo a vedere in pratica quello che abbiamo visto in teoria.
Creare una applicazione ben strutturata non vuole certo dire che funzionerà; quello che la rende funzionante è il codice che ci scriviamo dentro; ma avere una sana e forte struttura ci permette di sviluppare tutto più rapidamente, riducendo al minimo errori architetturali che possono venire fuori durante lo sviluppo, e che potrebbe rendere necessario un refactoring, cosa che è sempre dolorosa in termini di tempo e costo.