juneau-rest-client
Maven Dependency

<dependency> <groupId>org.apache.juneau</groupId> <artifactId>juneau-rest-client</artifactId> <version>8.0.0</version> </dependency>

Java Library

juneau-rest-client-8.0.0.jar

OSGi Module

org.apache.juneau.rest.client_8.0.0.jar

The REST client API allows you to access REST interfaces using POJOs:

// Create a reusable JSON client. RestClient client = RestClient.create().build(); // The address of the root resource. String url = "http://localhost:10000/systemProperties"; // Do a REST GET against a remote REST interface and convert // the response to an unstructured ObjectMap object. Map m1 = client.doGet(url).getResponse(TreeMap.class); // Add some new system properties. // Use XML as the transport medium. client = RestClient.create().serializer(XmlSerializer.class).parser(XmlParser.class).build(); Properties p = new Properties(); p.load(reader); int returnCode = client.doPost(url + "/systemProperties", p).execute();

The client API uses the same serializers and parsers (and subsequently their flexibility and configurability) as the server side to marshall POJOs back and forth.

More Information:

restRPC (RPC over REST) allows the creation of client-side remote proxy interfaces for calling methods on server-side POJOs using entirely REST.

// Get an interface proxy. IAddressBook ab = restClient.getRemoteInterface(IAddressBook.class); // Invoke a method on the server side and get the returned result. Person p = ab.createPerson( new Person( "John Smith", "Aug 1, 1999", new Address("My street", "My city", "My state", 12345, true) ) );

More Information:

The juneau-rest-client library can also be used to define interface proxies against 3rd-party REST interfaces. This is an extremely powerful feature that allows you to quickly define easy-to-use interfaces against virtually any REST interface.

Similar in concept to restRPC services defined above, but in this case we simply define our interface with special annotations that tell us how to convert input and output to HTTP headers, query parameters, form post parameters, or request/response bodies.

Example:

@RemoteResource(path="/petstore") public interface PetStore { @RemoteMethod(httpMethod=POST, path="/pets") String addPet( @Body CreatePet pet, @Header("E-Tag") UUID etag, @Query("debug") boolean debug ); }

// Use a RestClient with default Simple JSON support. try (RestClient client = RestClient.create().simpleJson().build()) { PetStore store = client.getRemoteResource(PetStore.class, "http://localhost:10000"); CreatePet pet = new CreatePet("Fluffy", 9.99); String response = store.createPet(pet, UUID.randomUUID(), true); }

The call above translates to the following REST call:

POST http://localhost:10000/petstore/pets?debug=true HTTP/1.1 Accept: application/json Content-Type: application/json E-Tag: 475588d4-0b27-4f56-9296-cc683251d314 { name: 'Fluffy', price: 9.99 }



A common coding practice is to use the same Java interface to define both your server and client side REST interfaces. The advantage to this approach is that changes that you make to your REST interface can be reflected in both places at the same time, reducing the chances for compatibility mistakes.

What makes this possible is that method-level annotations such as @RestMethod and parameter-level annotations such as @Query are inherited from parent classes. This normally isn't possible, but the framework will spider up the parent hierarchy of classes to find method and parameter level annotations defined on overridden methods.

The general approach is to define your @RemoteResource-annotated interface first. The following example is pulled from the PetStore app:

@RemoteResource(path="/petstore") public interface PetStore { @RemoteMethod(method=GET, path="/pet") public Collection<Pet> getPets() throws NotAcceptable; @RemoteMethod(method=DELETE, path="/pet/{petId}") public Ok deletePet( @Header( name="api_key", description="Security API key", required=true, example="foobar" ) String apiKey, @Path( name="petId", description="Pet id to delete", example="123" ) long petId ) throws IdNotFound, NotAcceptable; ...

Next you define the implementation of your interface as a normal Juneau REST resource:

@RestResource( path="/petstore", title="Petstore application", ... ) public class PetStoreResource extends BasicRestServlet implements PetStore { ... @Override /* PetStore */ @RestMethod( name=GET, path="/pet", summary="All pets in the store", ... ) public Collection<Pet> getPets() throws NotAcceptable { return store.getPets(); } @Override /* PetStore */ @RestMethod( name=DELETE, path="/pet/{petId}", summary="Deletes a pet", ... ) public Ok deletePet(String apiKey, long petId) throws IdNotFound, NotAcceptable { store.removePet(petId); return OK; }

Then use the interface as a remote resource like so:

try (RestClient rc = RestClient.create().json().rootUrl("http://localhost:10000").build()) { PetStore ps = rc.getRemoteResource(PetStore.class); for (Pet x : ps.getPets()) { ps.deletePet("my-special-key", x.getId()); System.out.println("Deleted pet: id=" + x.getId()); } }

More Information: