API client RESTEasy

1. Introduzione

Nell'articolo precedente ci siamo concentrati sull'implementazione lato server RESTEasy di JAX-RS 2.0 .

JAX-RS 2.0 introduce una nuova API client in modo da poter effettuare richieste HTTP ai servizi Web RESTful remoti. Jersey, Apache CXF, Restlet e RESTEasy sono solo un sottoinsieme delle implementazioni più popolari.

In questo articolo esploreremo come utilizzare l' API REST inviando richieste con un'API RESTEasy .

2. Configurazione del progetto

Aggiungi nel tuo pom.xml la seguente dipendenza:

 3.0.14.Final    org.jboss.resteasy resteasy-client ${resteasy.version}  ... 

3. Codice lato client

L'implementazione del client è abbastanza, essendo composta da 3 classi principali:

    • Cliente
    • WebTarget
    • Risposta

L' interfaccia client è un generatore di istanze WebTarget .

WebTarget rappresenta un URL distinto o un modello di URL da cui è possibile creare più WebTarget di risorse secondarie o richiamare richieste.

Ci sono davvero due modi per creare un cliente:

  • Il modo standard, utilizzando org.jboss.resteasy.client.ClientRequest
  • RESTeasy Proxy Framework : utilizzando la classe ResteasyClientBuilder

Ci concentreremo qui su RESTEasy Proxy Framework.

Invece di utilizzare le annotazioni JAX-RS per mappare una richiesta in entrata al metodo del servizio Web RESTFul, il framework client crea una richiesta HTTP che utilizza per invocare un servizio Web RESTful remoto.

Quindi iniziamo a scrivere un'interfaccia Java e utilizzare le annotazioni JAX-RS sui metodi e sull'interfaccia.

3.1. L' interfaccia ServicesClient

@Path("/movies") public interface ServicesInterface { @GET @Path("/getinfo") @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) Movie movieByImdbId(@QueryParam("imdbId") String imdbId); @POST @Path("/addmovie") @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) Response addMovie(Movie movie); @PUT @Path("/updatemovie") @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) Response updateMovie(Movie movie); @DELETE @Path("/deletemovie") Response deleteMovie(@QueryParam("imdbId") String imdbId); } 

3.2. La classe di film

@XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "movie", propOrder = { "imdbId", "title" }) public class Movie { protected String imdbId; protected String title; // getters and setters }

3.3. La creazione della richiesta

Ora genereremo un client proxy che possiamo utilizzare per utilizzare l'API:

String transformerImdbId = "tt0418279"; Movie transformerMovie = new Movie("tt0418279", "Transformer 2"); final String path = "//127.0.0.1:8080/RestEasyTutorial/rest"; ResteasyClient client = new ResteasyClientBuilder().build(); ResteasyWebTarget target = client.target(UriBuilder.fromPath(path)); ServicesInterface proxy = target.proxy(ServicesInterface.class); // POST Response moviesResponse = proxy.addMovie(transformerMovie); System.out.println("HTTP code: " + moviesResponse.getStatus()); moviesResponse.close(); // GET Movie movies = proxy.movieByImdbId(transformerImdbId); // PUT transformerMovie.setTitle("Transformer 4"); moviesResponse = proxy.updateMovie(transformerMovie); moviesResponse.close(); // DELETE moviesResponse = proxy.deleteMovie(batmanMovie.getImdbId()); moviesResponse.close(); 

Notare che l'API del client RESTEasy è basata su Apache HttpClient .

Si noti inoltre che, dopo ogni operazione, sarà necessario chiudere la risposta prima di poter eseguire una nuova operazione. Ciò è necessario perché, per impostazione predefinita, il client ha solo una singola connessione HTTP disponibile.

Infine, nota come stiamo lavorando direttamente con i DTO - non abbiamo a che fare con la logica di marshalling / unmarshal da e verso JSON o XML ; ciò accade dietro le quinte usando JAXB o Jackson poiché la classe Movie è stata annotata correttamente .

3.4. La creazione della richiesta con il pool di connessioni

Una nota dell'esempio precedente era che avevamo solo una singola connessione disponibile. Se, ad esempio, proviamo a fare:

Response batmanResponse = proxy.addMovie(batmanMovie); Response transformerResponse = proxy.addMovie(transformerMovie); 

senza invocare close () su batmanResponse - verrà lanciata un'eccezione quando viene eseguita la seconda riga:

java.lang.IllegalStateException: Invalid use of BasicClientConnManager: connection still allocated. Make sure to release the connection before allocating another one. 

Ancora una volta, questo accade semplicemente perché l' HttpClient predefinito utilizzato da RESTEasy è org.apache.http.impl.conn.SingleClientConnManager , che ovviamente rende disponibile solo una singola connessione.

Ora, per aggirare questa limitazione, l' istanza RestEasyClient deve essere creata in modo diverso (con un pool di connessioni):

PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(); CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(cm).build(); cm.setMaxTotal(200); // Increase max total connection to 200 cm.setDefaultMaxPerRoute(20); // Increase default max connection per route to 20 ApacheHttpClient4Engine engine = new ApacheHttpClient4Engine(httpClient); ResteasyClient client = new ResteasyClientBuilder().httpEngine(engine).build(); ResteasyWebTarget target = client.target(UriBuilder.fromPath(path)); ServicesInterface proxy = target.proxy(ServicesInterface.class);

Ora possiamo beneficiare di un pool di connessioni appropriato e possiamo avere più richieste in esecuzione attraverso il nostro client senza dover necessariamente rilasciare la connessione ogni volta.

4. Conclusione

In questo breve tutorial abbiamo introdotto RESTEasy Proxy Framework e con esso abbiamo costruito un'API client semplicissima.

Il framework ci offre alcuni metodi di supporto in più per configurare un client e può essere definito come il mirror opposto alle specifiche lato server JAX-RS.

L'esempio utilizzato in questo articolo è disponibile come progetto di esempio in GitHub.