WIP: Driving the initial version from this README, please feel free to provide feedback through issues.
Build safer and more resilient distributed services. Get the benefits of an always async approach to data exchange. Ensure decoupling of components. Be better prepared for system evolution. Create more scalable solutions. Change the way you think and design, by using Query/Response for Spring AMQP.
The fluid Query/Response API, makes it easy for developers and understand and decide on a strategy for service integration. Timeouts are first-class citizens in the API, and protect against surprises.
var authors = QueryBuilder.queryFor("authors", String.class)
.waitingFor(800)
.orEmpty();
Defaults are suddenly top-of-mind for developers, and either the empty case is good enough, or fallbacks can be provided.
var authors = QueryBuilder.queryFor("authors", String.class)
.waitingFor(800)
.orDefaults(Authors.defaults());
Preserve resources, specific to the current needs and protect your services, by limiting the amount of data consumed.
var authors = QueryBuilder.queryFor("authors", String.class)
.takingAtMost(10)
.waitingFor(800)
.orDefaults(Authors.defaults());
Express constraints and react accordingly, throwing on an unfulfilled query, as an option to lenient handling with defaults.
var offers = QueryBuilder.queryFor("offers/rental", Offer.class)
.takingAtLeast(10)
.takingAtMost(20)
.waitingFor(2, ChronoUnit.SECONDS)
.orThrow(TooFewOffersConstraintException::new);
Optional capabilities, to handle exceptions and errors are built-in and very easy to use.
var offers = QueryBuilder.queryFor("offers/rental", NewOffer.class)
.takingAtLeast(3)
.waitingFor(400)
.onError(error -> LOG.error("Failure!", error))
.orThrow(TooFewOffersConstraintException::new);
To create responding services we provide a really effective and expressive fluid-API. Developers benefit from the declarative style, and won't have to write any boilerplate code. It is easy to understand, work with and explore.
Very simple scenarios can quickly be created, for tests or proof of concept work.
ResponseBuilder.respondTo("authors", String.class)
.withAll()
.from("William Gibson", "Isaac Asimov", "J.R.R. Tolkien");
Batch responses provide developers with more options to tune and throttle a system using Query/Response across many services.
ResponseBuilder.respondTo("offers/monday", Offer.class)
.withBatchesOf(20)
.from(offers.findAllOffersByDayOfWeek(Calendar.MONDAY));
Dynamic responses are easy to build, with an API that fits modern Java, using lazy calls to data sources.
ResponseBuilder.respondTo("users/current", Token.class)
.withBatchesOf(128)
.suppliedBy(userTokenService::findAllCurrentUserTokens);
The declared AMQP broker resources are very limited. Only the query-response
topic-exchange is created. All active Query/Response services will automatically
declare the required exchange, with the following parameters:
name: query-response
type: topic
auto-delete: true
The Query/Response library defines a small set of properties and data-formats, which are used in the AMQP messages - a mini-protocol:
Query messages are very simple in structure and form. The common query-response
exchanged is published to, and the message routing-key
will carry the specific
query-term
that is requested. The reply-to
header property is set to the
queue name of a generated query-response-queue
, specific to the published
query.
Both query and response messages use the application/json
content-type. There
is no further content in the body, just an empty JSON object {}
, as a
placeholder.
exchange: query-response
routing-key: ${query-term}
reply-to: ${query-response-queue}
content-type: application/json
body:
{}
Published responses also use a common format. They are published to the empty
(default) exchange, with the query-response-queue
from the reply-to
property
of a consumed query as the routing-key
. This will cause a direct routing of
responses back to the declared response-queue.
The response body payload JSON structure always contains count
and total
properties. This is meta-information which provide consumers with hints on
possible paged responses. The elements
collection contain the actual response
data.
exchange: (default)
routing-key: ${query-response-queue}
content-type: application/json
body:
{
count: 42,
total: 1337,
elements: [...]
}
Happy hacking!
Spring is a trademark of Pivotal Software, Inc. in the U.S. and other countries.