Maven Dependency

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

Java Library


OSGi Module


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.

The remote proxy interface API allows you to invoke server-side POJO methods on the client side using REST (i.e. RPC over REST):

// Get an interface proxy. IAddressBook ab = restClient.getRemoteableProxy(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) ) );

Although the client API is not dependent on the juneau-rest-server module, the server module provides some convenience APIs for exposing remoteable proxies on the server side:

  1. Extending from RemoteableServlet.
  2. Using a @RestMethod(name=PROXY) annotation on a Java method.

The RemoteableServlet class is a simple specialized servlet with an abstract getServiceMap() method to define the server-side POJOs:

@RestResource( path="/remote" ) public class SampleRemoteableServlet extends RemoteableServlet { // Our server-side POJO. AddressBook addressBook = new AddressBook(); @Override /* RemoteableServlet */ protected Map<Class<?>,Object> getServiceMap() throws Exception { Map<Class<?>,Object> m = new LinkedHashMap<Class<?>,Object>(); // In this simplified example, we expose the same POJO service under two different interfaces. // One is IAddressBook which only exposes methods defined on that interface, and // the other is AddressBook itself which exposes all methods defined on the class itself (dangerous!). m.put(IAddressBook.class, addressBook); m.put(AddressBook.class, addressBook); return m; } }

The @RestMethod(name=PROXY) approach is easier if you only have a single interface you want to expose. You simply define a Java method whose return type is an interface, and return the implementation of that interface:

// Our exposed proxy object. @RestMethod(name=PROXY, path="/addressbookproxy/*") public IAddressBook getProxy() { return addressBook; }

In either case, the proxy communications layer is pure REST. Parameters passed in on the client side are serialized as an HTTP POST, parsed on the server side, and then passed to the invocation method. The returned POJO is then marshalled back as an HTTP response.

In most cases, you'll want to use JSON or MessagePack as your communications layer since these are the most efficient. Although remoteable proxies work perfectly well for any of the other supported languages. For example, RPC over Turtle!

The parameters and return types of the Java methods can be any of the supported serializable and parsable types in POJO Categories. This ends up being WAY more flexible than other proxy interfaces since Juneau can handle so may POJO types out-of-the-box. Most of the time you don't even need to modify your existing Java implementation code.

The RemoteableServlet class itself shows how sophisticated REST interfaces can be built on the Juneau REST Servlet API using very little code. The class consists of only 53 lines of code, yet is a sophisticated discoverable and self-documenting REST interface. And since the remote proxy API is built on top of REST, it can be debugged using just a browser.

Remoteable proxies 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 remoteable 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.

@Remoteable public interface MyProxyInterface { @RemoteMethod(httpMethod=POST, path="/method") String doSomething(@Header("E-Tag") UUID etag, @Query("debug") boolean debug, @Body MyPojo pojo); } RestClient client = ConfigFile.create().build(); // Default is JSON MyProxyInterface p = client.getRemoteableProxy(MyProxyInterface.class, "http://hostname/some/rest/interface"); String response = p.doSomething(UUID.generate(), true, new MyPojo());