= Vert.x Web API Service
:toc: left

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 https://vertx.io/docs/vertx-core/java/#event_bus[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 https://vertx.io/docs/vertx-service-proxy/java/[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`):

[source,xml,subs="+attributes"]
----
<dependency>
  <groupId>io.vertx</groupId>
  <artifactId>vertx-codegen</artifactId>
  <version>5.0.0.CR1</version>
  <classifier>processor</classifier>
</dependency>
<dependency>
  <groupId>io.vertx</groupId>
  <artifactId>vertx-web-api-service</artifactId>
  <version>5.0.0.CR1</version>
</dependency>
----

* Gradle < 5 (in your `build.gradle` file):

[source,groovy,subs="+attributes"]
----
dependencies {
  compile 'io.vertx:vertx-codegen:5.0.0.CR1:processor'
  compile 'io.vertx:vertx-web-api-service:5.0.0.CR1'
}
----

* Gradle >= 5 (in your `build.gradle` file):

[source,groovy,subs="+attributes"]
----
dependencies {
  annotationProcessor 'io.vertx:vertx-codegen:5.0.0.CR1:processor'
  annotationProcessor 'io.vertx:vertx-web-api-service:5.0.0.CR1'
  compile 'io.vertx:vertx-web-api-service:5.0.0.CR1'
}
----

You need to import `vertx-codegen` to trigger the code generation from annotated interfaces.
If you need only the `link:../../apidocs/io/vertx/ext/web/api/service/RouteToEBServiceHandler.html[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 `link:../../apidocs/io/vertx/ext/web/api/service/RouteToEBServiceHandler.html[RouteToEBServiceHandler]`.
This handler sends some data extracted from `link:../../apidocs/io/vertx/ext/web/RoutingContext.html[RoutingContext]` inside a `link:../../apidocs/io/vertx/ext/web/api/service/ServiceRequest.html[ServiceRequest]` and expects a
`link:../../apidocs/io/vertx/ext/web/api/service/ServiceResponse.html[ServiceResponse]` as reply.

[source,java]
----
router
  .get("/hello")
  .handler(validationHandler)
  .handler(
    RouteToEBServiceHandler
      .build(eventBus, "greeters.myapplication", "hello")
  );
----

You can also define the `link:../../apidocs/io/vertx/core/eventbus/DeliveryOptions.html[DeliveryOptions]` that will be used each time a message is sent through the event bus:

[source,java]
----
router
  .get("/hello")
  .handler(validationHandler)
  .handler(
    RouteToEBServiceHandler
      .build(eventBus, "greeters.myapplication", "hello",
        new DeliveryOptions().setSendTimeout(1000))
  );
----

IMPORTANT: Before mounting the `link:../../apidocs/io/vertx/ext/web/api/service/RouteToEBServiceHandler.html[RouteToEBServiceHandler]`, you *must* mount a
`link:../../apidocs/io/vertx/ext/web/validation/ValidationHandler.html[ValidationHandler]` that extracts the request parameters.
Otherwise, no request parameters will be sent.

== Define your Web API Service interface

We encourage you to read https://vertx.io/docs/vertx-service-proxy/java/[Service Proxy documentation] before going further

Let's assume we have defined two different routes in our `link:../../apidocs/io/vertx/ext/web/Router.html[Router]` as follows:

[source,java]
----
router.get("/api/transactions")
  .handler(
    ValidationHandlerBuilder.create(repository)
      .queryParameter(optionalParam("from", stringSchema()))
      .queryParameter(optionalParam("to", stringSchema()))
      .build()
  ).handler(
    RouteToEBServiceHandler.build(eventBus, "transactions.myapplication",
      "getTransactionsList")
  );
router.post("/api/transactions")
  .handler(
    ValidationHandlerBuilder.create(repository)
      .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 `link:../../apidocs/io/vertx/core/json/JsonObject.html[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 `link:../../apidocs/io/vertx/ext/web/api/service/RouteToEBServiceHandler.html[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 `link:../../apidocs/io/vertx/ext/web/api/service/ServiceRequest.html[ServiceRequest]`
* All parameters from first to second to last (excluded) are extracted from `link:../../apidocs/io/vertx/ext/web/validation/RequestParameters.html[RequestParameters]` with specified type automatically, but they need to respect https://vertx.io/docs/vertx-service-proxy/java/#_restrictions_for_service_interface[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:

[source,java]
----
@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 `link:../../apidocs/io/vertx/ext/web/api/service/ServiceRequest.html[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:

[source,java]
----
void putTransaction(Transaction body, ServiceRequest context, Handler<AsyncResult<ServiceResponse>> resultHandler);
----

You can also use `link:../../apidocs/io/vertx/ext/web/validation/RequestParameter.html[RequestParameter]` to extract parameters, like:

[source,java]
----
void putTransaction(RequestParameter body, ServiceRequest context, Handler<AsyncResult<ServiceResponse>> resultHandler);
----

We encourage to extract with `link:../../apidocs/io/vertx/ext/web/validation/RequestParameter.html[RequestParameter]` type the parameters that uses json schema allOf/anyOf/oneOf/not keywords because the extraction can produce undefined behaviours.

NOTE: 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 `link:../../apidocs/io/vertx/ext/web/api/service/ServiceRequest.html[ServiceRequest]` object contains headers and parameters maps.

To write the request you must call the `resultHandler` with an `link:../../apidocs/io/vertx/ext/web/api/service/ServiceResponse.html[ServiceResponse]`.
To create an instance of `link:../../apidocs/io/vertx/ext/web/api/service/ServiceResponse.html[ServiceResponse]` you can use some handy methods like `link:../../apidocs/io/vertx/ext/web/api/service/ServiceResponse.html#completedWithJson-io.vertx.core.buffer.Buffer-[ServiceResponse.completedWithJson]` or `link:../../apidocs/io/vertx/ext/web/api/service/ServiceResponse.html#completedWithPlainText-io.vertx.core.buffer.Buffer-[ServiceResponse.completedWithPlainText]`

For example the implementation of `TransactionService#getTransactionsList` looks like:

[source,java]
----
resultHandler.handle(
  Future.succeededFuture(
    ServiceResponse.completedWithJson(new JsonArray())
  )
);
----

Or when it fails:

[source,java]
----
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:

* `link:../../apidocs/io/vertx/ext/web/api/service/ServiceRequest.html#getHeaders--[getHeaders]`: Headers of the request
* `link:../../apidocs/io/vertx/ext/web/api/service/ServiceRequest.html#getParams--[getParams]`: Contains `routingContext.get("parsedParameters")`
* `link:../../apidocs/io/vertx/ext/web/api/service/ServiceRequest.html#getUser--[getUser]`: Contains `routingContext.user().principal()`, null if no user is authenticated
* `link:../../apidocs/io/vertx/ext/web/api/service/ServiceRequest.html#getExtra--[getExtra]`: Contains an extra configurable payload

You can configure a lambda that builds the extra payload with `link:../../apidocs/io/vertx/ext/web/api/service/RouteToEBServiceHandler.html#extraPayloadMapper-java.util.function.Function-[extraPayloadMapper]`

=== The `ServiceResponse` data object

`ServiceResponse` is composed by:

* Headers of the response
* Status code/Status message
* Body as a payload.
If you don't set the payload/set as null no body will be sent

== Expose your Web API Service

Now you can register your service to event bus:

[source,java]
----
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 https://vertx.io/docs/vertx-service-proxy/java/#_exposing_your_service[Vert.x service proxy documentation]

== OpenAPI Integration

Vert.x Web API Service offers an `link:../../apidocs/io/vertx/ext/web/api/service/OpenAPIRouterHandler.html[OpenAPIRouterHandler]` which can be added to an `link:../../apidocs/io/vertx/ext/web/openapi/router/OpenAPIRoute.html[OpenAPIRoute]` and will forward incoming HTTP requests to the related Web API Service Proxy.
The validation of this `link:../../apidocs/io/vertx/ext/web/openapi/router/OpenAPIRoute.html[OpenAPIRoute]` *MUST* be enabled.

[source,java]
----
OpenAPIContract contract = getContract();
ResponseValidator responseValidator = ResponseValidator.create(vertx, contract);

OpenAPIRoute route = routerBuilder.getRoute("getPets");
OpenAPIRouterHandler handler = OpenAPIRouterHandler.create(vertx,
  route.getOperation(), responseValidator);

route.addHandler(handler);
----

=== OpenAPI contract extension

Adding an `link:../../apidocs/io/vertx/ext/web/api/service/OpenAPIRouterHandler.html[OpenAPIRouterHandler]` to an `link:../../apidocs/io/vertx/ext/web/openapi/router/OpenAPIRoute.html[OpenAPIRoute]` requires to extend the related `OpenAPI Operation` with a `x-vertx-event-bus` extension.
The `x-vertx-event-bus` extension must be filled with the address and method name of the related Web API Service Proxy.
If no method name is defined, the operationId will be used.

[source,yaml]
----
# without method name
paths:
  /pets:
    get:
      operationId: listPets
      x-vertx-event-bus: myEventbusAddress

# with method name
paths:
  /pets:
    get:
      operationId: listPets
      x-vertx-event-bus:
        address: myEventbusAddress
        method: getPetById

# defined on Path level for all operations
paths:
  /pets:
    x-vertx-event-bus: myEventbusAddress
    get:
      operationId: listPets
    post:
      operationId: createPet
----