Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
There is lots of support for writing REST APIs in Java; there
are fewer options for writing REST clients (some existing
ones are described
here).
This library is the result of its author needing to write a REST client
one too many times and not being satisfied with the options, and wanting
one with an asynchronous, callback-based API - if you are writing an
asynchronous
web service which needs to call another web service, and calling the
remote service is not asynchronous too, then you instantly go from
having a massively scalable web API to having one which is blocked
doing I/O and scales worse than old-fashioned threaded alternatives.
Calling REST APIs is simple enough that it's commonplace to do it with
plain old Java code. But what inevitably happens is that an entire
codebase gets littered with boilerplate such as setting content types,
literal paths and URLs and similar noise-code. Then one day the API
changes, and finding all of the places the code must be updated is a long,
expensive and painful job that usually misses some cases.
The idea here is to use some of Guice's injection features under the
hood to make it very simple to define elements of a web API and pass
arguments to construct a web call. So you deal in objects, and those
get translated into an HTTP call in a well-defined way in a well-defined
place, but you don't have to write a lot of code to do those calls.
It means that making a web call
involves no repetitive boilerplate, and for most common cases, things
like interpreting the response are handled. More importantly, it
keeps things like URL paths all located in one place, so refactoring of
a web api doesn't mean grepping your source code. To call a web api,
you simply pass an enum constant representing that call to an
Invoker, and some
objects to flesh out the call's URL, headers and or body - and you can
literally pass as many objects in whatever order as you want - the
signature is
invoker.call(Enum<?> call, Callback<T> callback, Object... args).
Defining the Web API you want to call
Your web api starts with a Java Enum which defines all of
the calls in the API. The enum must implement
WebCallEnum which has a
single method, get() which returns an instance of
WebCall. The enum serves as a handy way to reference
API calls, and a way that the system (which uses Guice to bind object
types) knows the entire list of types which might be used to construct
web calls.
Here's a sample API with two calls, one which says hello and one which
echoes back the request body sent to it.
How do we use it? Very simply. First, we need an instance of an
Invoker; you can either
create one using Guice (you need to bind a base URL and an HttpClient),
or use a static method to have it do that for you:
Then we need a callback which will be
called when our call completes - it gets passed the result and can
do whatever you need to with it:
Callback<Map> c = new Callback<Map>(Map.class) {
public void success(Map object) {
System.out.println("YAY: " + object);
}
public void fail(HttpResponseStatus status, ByteBuf bytes) {
System.out.println("FAILED WITH " + status);
}
};
Then we simply pass the callback, and some arguments, to the invoker:
ResponseFuture f = invoker.call(TestAPI.HELLO_WORLD, c,
new DisplayName("Tim Boudreau"), new UserId("tim"));
When the request completes, or if it fails, our callback will be called
(there are a few other methods, such as exception handling, which can
optionally be overridden).
Under the hood, what happens is this:
We look up the path template tied to this web call - in
this case /users/{{userid}}/hello. The {{userid}}
part will be substituted. Fancy substitutions are possible by
writing your own Interpolator,
but "userid" matches the lower case name of the class UserId -
and we passed one in. So its toString() is called, and
"{{userid}}" is replaced with "tim".
When we created the call, you may have noticed the line
.withDecorator(DisplayName.class, ParameterFromClassNameAndToStringCamelCase.class).
We have a DisplayName class which is also a wrapper
for a string. ParameterFromClassNameAndToStringCamelCase
is a Decorator which
ships with this library. It simply takes the simple class name and
lower-cases it, and uses toString() on the value to
construct a query parameter. So the actual URL we will call is
now http://server.example/users/tim/hello?displayName=Tim+Boudreau
An HTTP request with an empty body is constructed and sent to
the server.
Our callback takes a Map as its parameter. So the
code will take the response body, interpret it as JSON and
convert the content to a Map (using Jackson) and
pass that to our callback. We could also have asked for the content
as an Image, String, ByteBuf, byte[], InputStream or Image, and it
could have be unmarshalled transparently as any of those things;
or if it is a type which Jackson can unmarshal from JSON, that
can be done automatically. For custom unmarshalling, you simply
implement Interpreter
and add that to your WebCall.
ResponseFuture
Making an API call returns a ResponseFuture
which you can use to cancel the call, or attach listeners to for events such
as the response being sent, the headers being sent back, or even individual
content chunks arriving.
It also has two await() methods which will block the calling
thread until the call has completed. They are useful in unit tests
and things like that; please don't use them in non-test code!
For an overview of why Future is an antipattern, see this abstract Why There’s No Future in Java Futures.
Essentially, the number one rule of using an asynchronous, message-based
API is don't block, ever.
Conclusions
The result is that calling a web api is dirt-simple, scalable, and
relatively intuitive; and since the entire definition of the API lives
in one place, refactoring is simple - no searching code or guessing
required.