<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-codegen</artifactId>
<version>4.5.11</version>
<classifier>processor</classifier>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-web-api-service</artifactId>
<version>4.5.11</version>
</dependency>
Vert.x Web API Service
Vert.x Web API Service helps you handling HTTP Requests using the Vert.x Event Bus.
Event Bus provides important features like load balancing and distribution of requests across different Vert.x instances. We encourage you to give a look at Event Bus documentation for more info.
This module gives you the ability to create a Web API Service, an event bus message consumer based on same concept of Vert.x service proxy. Then it provides an handler to proxy the request to these services.
Using Vert.x API Service
To use Vert.x API Service, add the following dependency to the dependencies section of your build descriptor:
-
Maven (in your
pom.xml
):
-
Gradle < 5 (in your
build.gradle
file):
dependencies {
compile 'io.vertx:vertx-codegen:4.5.11:processor'
compile 'io.vertx:vertx-web-api-service:4.5.11'
}
-
Gradle >= 5 (in your
build.gradle
file):
dependencies {
annotationProcessor 'io.vertx:vertx-codegen:4.5.11:processor'
annotationProcessor 'io.vertx:vertx-web-api-service:4.5.11'
compile 'io.vertx:vertx-web-api-service:4.5.11'
}
You need to import vertx-codegen
to trigger the code generation from annotated interfaces. If you need only the RouteToEBServiceHandler
, you don’t need it
If you want to use the interface you write in different languages, you will need to add the language dependency such as vertx-lang-groovy
for Groovy.
Proxy an HTTP Request to a Web API Service
To proxy a request to the event bus you can use RouteToEBServiceHandler
. This handler sends some data extracted from RoutingContext
inside a ServiceRequest
and expects a ServiceResponse
as reply.
router
.get("/hello")
.handler(validationHandler)
.handler(
RouteToEBServiceHandler
.build(eventBus, "greeters.myapplication", "hello")
);
You can also define the DeliveryOptions
that will be used each time a message is sent through the event bus:
router
.get("/hello")
.handler(validationHandler)
.handler(
RouteToEBServiceHandler
.build(eventBus, "greeters.myapplication", "hello", new DeliveryOptions().setSendTimeout(1000))
);
Before mounting the RouteToEBServiceHandler , you must mount a ValidationHandler that extracts the request parameters. Otherwise, no request parameters will be sent. |
Define your Web API Service interface
We encourage you to read Service Proxy documentation before going further
Let’s assume we have defined two different routes in our Router
as follows:
router.get("/api/transactions")
.handler(
ValidationHandlerBuilder.create(schemaParser)
.queryParameter(optionalParam("from", stringSchema()))
.queryParameter(optionalParam("to", stringSchema()))
.build()
).handler(
RouteToEBServiceHandler.build(eventBus, "transactions.myapplication", "getTransactionsList")
);
router.post("/api/transactions")
.handler(
ValidationHandlerBuilder.create(schemaParser)
.body(json(objectSchema()))
.build()
).handler(
RouteToEBServiceHandler.build(eventBus, "transactions.myapplication", "putTransaction")
);
GET /api/transactions
receives two optional query parameters as input: from
and to
. PUT /api/transactions
receives a JsonObject
as request body
Now we can build the interface TransactionService that handles those endpoints. For each endpoint you need to write a method with name corresponding to action
specified when you build the RouteToEBServiceHandler
. There are a couple of rules to follow for method parameters:
-
Last parameter must have type
Handler<AsyncResult<ServiceResponse>>
-
Second to last parameter must have type
ServiceRequest
-
All parameters from first to second to last (excluded) are extracted from
RequestParameters
with specified type automatically, but they need to respect service proxy restrictions
A request parameter is identified only by the name of the method parameter and the special body
method parameter name is used to extract the body of the request.
For example:
@WebApiServiceGen
interface TransactionService {
void getTransactionsList(String from, String to, ServiceRequest context, Handler<AsyncResult<ServiceResponse>> resultHandler);
void putTransaction(JsonObject body, ServiceRequest context, Handler<AsyncResult<ServiceResponse>> resultHandler);
}
When you receive a request at TransactionService#getTransactionsList
the generated service handler will automatically extract from
and to
parameter (if present) from ServiceRequest
. In TransactionService#putTransaction
we use the body
parameter name to extract the json body.
The service handler is also capable to translate JsonObject
to Vert.x data objects automatically, for example if you have a Transaction
data object that matches the json schema above, you can rewrite the putTransaction
signature as:
void putTransaction(Transaction body, ServiceRequest context, Handler<AsyncResult<ServiceResponse>> resultHandler);
You can also use RequestParameter
to extract parameters, like:
void putTransaction(RequestParameter body, ServiceRequest context, Handler<AsyncResult<ServiceResponse>> resultHandler);
We encourage to extract with RequestParameter
type the parameters that uses json schema allOf/anyOf/oneOf/not keywords because the extraction can produce undefined behaviours.
When working with DataObjects by default base64 strings are handled with the base64url alphabet, while OpenAPI does not mandate this alphabet so it assumes basic . To force a DataObject to use a specific alphabet this can be configured in the @DataObject annotation. |
Implement your Web API Service
Now you can implement your service. Remember that ServiceRequest
object contains headers and parameters maps.
To write the request you must call the resultHandler
with an ServiceResponse
. To create an instance of ServiceResponse
you can use some handy methods like ServiceResponse.completedWithJson
or ServiceResponse.completedWithPlainText
For example the implementation of TransactionService#getTransactionsList
looks like:
resultHandler.handle(
Future.succeededFuture(
ServiceResponse.completedWithJson(new JsonArray())
)
);
Or when it fails:
resultHandler.handle(
Future.failedFuture(
new HttpException(555, "Something bad happened")
)
);
The ServiceRequest
data object
ServiceRequest
it’s a serializable version of RoutingContext
, but It doesn’t contain all data of RoutingContext
. It transports to your service:
-
getHeaders
: Headers of the request -
getParams
: ContainsroutingContext.get("parsedParameters")
-
getUser
: ContainsroutingContext.user().principal()
, null if no user is authenticated -
getExtra
: Contains an extra configurable payload
You can configure a lambda that builds the extra payload with extraPayloadMapper
Expose your Web API Service
Now you can register your service to event bus:
TransactionService transactionService = new TransactionServiceImpl();
// Mount the service on the event bus
ServiceBinder transactionServiceBinder = new ServiceBinder(vertx);
transactionServiceBinder
.setAddress("transactions.myapplication")
.register(TransactionService.class, transactionService);
For more info on how to expose your service look at Vert.x service proxy documentation