
Quando ci si trova a creare delle API REST si deve spesso fronteggiare dei framework piuttosto complessi la cui sola configurazione richiede un bel pò di lavoro. Il progetto di cui parliamo in questo tutorial, Spark Java, si pone lo scopo di creare velocemente delle API REST partendo da un semplice metodo main di un programma Java sfruttando la sintassi della rivoluzionaria versione 8 del linguaggio.
Integrare Spark Java
Nel nostro esempio, metteremo alla prova il framework approntando un semplice servizio web che si occupa di eseguire un’unica operazione aritmetica: la divisione. Passeremo gli operandi come parametri HTTP e staremo ben attenti a controllare gli errori facendo leva sempre su quello che Spark Java offre.
Per integrare Spark Java, utilizziamo Maven ed inseriamo le seguenti dipendenze nel file pom.xml:
<dependency> <groupId>com.sparkjava</groupId> <artifactId>spark-core</artifactId> <version>2.5</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>1.7.21</version> </dependency>
La prima delle due è la libreria che vogliamo utilizzare, la seconda è uno strumento per il logging.
Per provare subito l’innovativo Spark, scriviamo un semplicissimo main e lanciamo il programma:
public class App { public static void main( String[] args ) { get("/test", (req, res) -> "Server in funzione..."); } }
Una volta avviato, avremo già un servizio web all’indirizzo http://localhost:4567/test che, se contattato, risponderà “Server in funzione…”.
Spark mette a disposizione una serie di metodi per tutte le classiche funzionalità REST: get, post, put, delete. In questo caso, gestiamo una chiamata di tipo GET, sul percorso /test. Il codice che definiscce l’azione da eseguire è definito con una espressione lambda – funzionalità introdotta con Java8 – che prende in ingresso due oggetti: req (la richiesta HTTP) e res (la risposta HTTP).
Come si vede, Spark incrocia semplicità e sintetiticità per raggiungere rapidamente l’obiettivo.
L’esempio: dividiamo numeri via HTTP
L’esempio che proponiamo, come detto, vuole rappresentare una divisione di due numeri eseguita via HTTP. Spark, di default, attiva il servizio web sulla porta TCP 4567 ma in questo caso vorremo attivarla sulla 11113. In pratica, quello che faremo sarà fare in modo che invocando l’indirizzo http://localhost:11113/divisione/45/5 ci verrà restituito il risultato della divisione tra 45 e 5 ossia 9. Basterà poi inviare altri numeri al posto di 45 e 5 e otterremo l’operazione tra due operandi diversi.
Questo il codice:
public class App { public static void main( String[] args ) { port(11113); get("/test", (req, res) -> "Server in funzione..."); get("/divisione/:op1/:op2", (req, res) -> { int op1=Integer.valueOf(req.params("op1")); int op2=Integer.valueOf(req.params("op2")); return op1/op2; }); } }
Abbiamo lasciato l’invocazione all’URL di test che abbiamo visto prima ma abbiamo:
- cambiato la porta del servizio con il metodo port, spostandolo sulla 11113 TCP;
- aggiunto una chiamata GET sull’indirizzo /divisione.
Notare i parametri della divisione come vengono trattati: inserendoli nell’URL, con l’apposizione dei due punti davanti, sarà come creare due variabili – op1 e op2 – che verranno di volta in volta valorizzate con i parametri passati. Si può fare accesso ai valori tramite il metodo params dell’oggetto rappresentante la richiesta HTTP.
Per sperimentare le operazioni è sufficiente avviare il programma ed invocarle da browser.
Filtri ed eccezioni
Immaginiamo di voler effettuare dei controlli sui dati prima che raggiungano i metodi: Spark mette a disposizione dei filtri che agiscono tramite il metodo before che, come dice il nome stesso, intercetta la richiesta “prima” che venga eseguita riservandosi così il potere di fermarla. In questo caso lo useremo per verificare che il divisore (il secondo parametro) sia diverso da zero, cosa che renderebbe impossibile la divisione, producendo un’eccezione. Aggiungiamo questa richiesta nel main:
before("/divisione/:op1/:op2", (req, res) -> { int divisore=Integer.valueOf(req.params("op2")); if (divisore==0) halt(401,"Divisore pari a 0"); });
Tramite il percorso indicheremo al metodo before quando intervenire e cosa fare: in caso di divisore nullo, il metodo halt restituirà errore HTTP 401 al client. Si noti che abbiamo indicato tale codice numerico solo a scopo di esempio ma, come si immagina, nell’uso reale si sceglierà quello più opportuno in base all’errore.
Effettuiamo il test di questa operazione tramite il client Postman ottimo per questo tipo di verifiche:
Cerchiata in rosso vediamo la richiesta mentre gli ellissi blu mostrano codice HTTP e descrizione nel corpo della risposta che sono i dati da noi predisposti nella gestione del metodo before. Analogamente, si può usare after per effettuare operazioni dopo l’esecuzione di una richiesta.
Qualora inviassimo un parametro non numerico, come il seguente http://localhost:11113/divisione/45/A il programma restituirebbe un’eccezione di tipo NumberFormatException al momento del parsing e ciò verrebbe reso come un errore generico lato server, codice 500. Spark dà la possibilità di definire come deve essere trattata un’eccezione ed in quale codice di stato HTTP deve essere convertito:
exception(NumberFormatException.class, (exception, req, res) -> { res.status(401); res.body("Fornire parametri numerici"); });
Anche in questo caso Postman fornisce il riscontro di cui abbiamo bisogno:
Conclusioni
Tanto per renderci conto della sinteticità ed espressività del linguaggio usato da Spark Java riproponiamo qui l’intero codice dell’esempio:
public class App { public static void main( String[] args ) { port(11114); get("/test", (req, res) -> "Server in funzione..."); get("/divisione/:op1/:op2", (req, res) -> { int op1=Integer.valueOf(req.params("op1")); int op2=Integer.valueOf(req.params("op2")); return op1/op2; }); before("/divisione/:op1/:op2", (req, res) -> { int divisore=Integer.valueOf(req.params("op2")); if (divisore==0) halt(401,"Divisore pari a 0"); }); exception(NumberFormatException.class, (exception, req, res) -> { res.status(401); res.body("Fornire parametri numerici"); }); } }
Tante funzionalità rese con poche invocazioni di metodi dimostrano una linearità che sembra quasi non appartenere al linguaggio Java, spesso molto prolisso, ma più ad un’app per Node.js.
Finisce qui il nostro primo appuntamento con Spark Java ma in altri tutorial lo vedremo impegnato nella realizzazione di API più complete.
Alla prossima!
No Responses to “Creare API REST velocemente con Spark Java”