private Future<Object> executeAndDecode(final RequestTemplate template) {
    final Request request = targetRequest(template);

    logRequest(request);

    final Instant start = Instant.now();

    return client
        .execute(request)
        .compose(
            response -> {
              final long elapsedTime = Duration.between(start, Instant.now()).toMillis();
              boolean shouldClose = true;

              try {
                // TODO: check why this buffering is needed
                if (logLevel != Logger.Level.NONE) {
                  response =
                      logger.logAndRebufferResponse(
                          metadata.configKey(), logLevel, response, elapsedTime);
                }

                if (Response.class == metadata.returnType()) {
                  if (response.body() == null) {
                    return Future.succeededFuture(response);
                  } else if (response.body().length() == null
                      || response.body().length() > MAX_RESPONSE_BUFFER_SIZE) {
                    shouldClose = false;
                    return Future.succeededFuture(response);
                  } else {
                    return Future.succeededFuture(
                        Response.builder()
                            .status(response.status())
                            .reason(response.reason())
                            .headers(response.headers())
                            .request(response.request())
                            .body(response.body())
                            .build());
                  }
                } else if (response.status() >= 200 && response.status() < 300) {
                  if (Void.class == metadata.returnType()) {
                    return Future.succeededFuture();
                  } else {
                    return Future.succeededFuture(decode(response, request));
                  }
                } else if (decode404 && response.status() == 404) {
                  return Future.succeededFuture(decoder.decode(response, metadata.returnType()));
                } else {
                  return Future.failedFuture(errorDecoder.decode(metadata.configKey(), response));
                }
              } catch (final IOException ioException) {
                logIoException(ioException, elapsedTime);
                return Future.failedFuture(errorReading(request, response, ioException));
              } catch (FeignException exception) {
                return Future.failedFuture(exception);
              } finally {
                if (shouldClose) {
                  ensureClosed(response.body());
                }
              }
            },
            failure -> {
              if (failure instanceof VertxException || failure instanceof TimeoutException) {
                return Future.failedFuture(failure);
              } else if (failure.getCause() instanceof IOException) {
                final long elapsedTime = Duration.between(start, Instant.now()).toMillis();
                logIoException((IOException) failure.getCause(), elapsedTime);
                return Future.failedFuture(
                    errorExecuting(request, (IOException) failure.getCause()));
              } else {
                return Future.failedFuture(failure.getCause());
              }
            });
  }
Executes request from {@code template} with {@code this.client} and decodes the response.
Result or occurred error wrapped in returned Future.

@param template request template
@return future with decoded result or occurred error
vertx/feign-vertx/src/main/java/feign/VertxMethodHandler.java