Alcuni giorni fa mi sono imbattuto in un problema che forse già in molti hanno dovuto affrontare e per il quale in pochi mi hanno saputo dare un consiglio o una risposta certa per risolverlo; vuoi per pigrizia o per mancanza di necessità insomma nessuno mi ha saputo dire con quale framework potevo risolvere il seguente problema: data una interfaccia Java con tanto di annotations JAX-RS (2.0) esiste un modo per generare un client Http in Java??
In termini di design-pattern ciò di cui avevo bisogno è un proxy Rest. Ci tengo ad enfatizzare questo aspetto poiché le parole chiave che mi hanno aiutato nella ricerca della soluzione si sono rivelate davvero importanti. Ma veniamo a noi....allora la buona notizia è che esiste una soluzione chiavi in mano, la cattiva notizia è che non si tratta di un metodo standard previsto dalla specifica JAX-RS, tuttavia sono pienamente convinto che la tecnica che vi mostrerò verrà sicuramente contemplata nelle future versioni dello standard. Allo scopo, ci viene in aiuto un framework, che mi ha fatto risparmiare un bel po' di tempo, trattasi di Resteasy: un REST framework sviluppato da JBoss.

Resteasy è paragonabile a framework come Jersey, Apache CXF o Spring Rest Template, in pratica tutti implementano la specifica JAX-RS e risolvono tutti lo stesso problema di base, in più ognuno offre qualche caratteristica aggiuntiva per agevolarci durante lo sviluppo di Rest Services.

Ad esempio, Reasteasy, come Jersey, offre un framework per la parte server-side, un framework per scrivere i test unitari e delle estensioni alle API lato client. Ovviamente le API lato client non sono necessarie se non abbiamo bisogno di invocare RestService da un ambiente diverso dal browser.

Come tutti sappiamo JAX-RS fornisce delle annotations per generare un servizio Rest da un interfaccia Java, o meglio per generare uno stub del servizio che è capace di coprire aspetti che normalmente un servizio Rest offre in quanto tale, ovvero binding dell'operazione al metodo HTTP, modalità di serializzazione dei dati, etc.
Ad esempio il seguente servizio, mappa due operazioni una di tipo GET e l'altro di tipo PUT:

public interface RestService
{
   @GET
   @Path("get")
   @Produces("text/plain")
   String get();

   @PUT
   @Path("put")
   @Consumes("text/plain")
   void put(String body);

}

Se dovessimo sviluppare un client rest normalmente dovremmo istanziare un client http e invocare le URL che mappano le operazioni REST, in più dovremmo controllare lo stato della risposta, leggere e deserializzare il payload. Con un set minimo di librerie base e un po' di integrazione si riuscirebbero a coprire tutti questi aspetti oppure possiamo decidere di usare Resteasy Proxy Framework che con poche linee di codice ci permetterà di fare tutto quello che abbiamo appena descritto .... e devo dire che lo fa anche bene :).
Quindi per generare il nostro proxy ci basterà utilizzare questo code snippet e il gioco è fatto:

Client client = ClientFactory.newClient();
WebTarget target = client.target("http://example.com/base/api");
ResteasyWebTarget rtarget = (ResteasyWebTarget)target;

RestService service = rtarget.proxy(RestService.class);
service.put("hi,  i'm invoking RestService in a simple way");

Il cuore di questo pezzo di codice è il metodo proxy. Ciò che abbiamo fatto è stato semplicemente passare l'interfaccia del servizio al metodo proxy in modo da farci restituire un client http funzionante. Da questo momento in poi tutte le chiamate ai metodi scateneranno delle richieste http che rispecchiano esattamente ciò che si aspetta il servizio descritto dalle annotation JAX-RS. In altre parole abbiamo ottenuto il lato opposto di ciò che normalmente fa un framework Rest per generare la parte server.

Buon
rest
client a tutti :)



  • submit to reddit
blog comments powered by Disqus