vertx-service-proxy
vertx-service-proxy copied to clipboard
Generated Proxies need to allow setting headers
The current proxy generator is very simple and does not take into consideration the headers in the event bus message. In a scenario where a user would want to send a Authentication token with the message to attest the id of the caller, this is currently not supported and requires the user to manually perform the marshalling, e.g.:
service = new MicroServiceVertxEBProxy(vertx, MicroService.ADDRESS);
vertx.eventBus()
.<String>request(MicroService.ADDRESS, new JsonObject(), new DeliveryOptions()
.addHeader("action", "execute")
.addHeader("auth-token", ctx.user().get("id_token")));
This example is simple as the service method execute takes no arguments. This approach avoids the current generator that is unable to set headers and would like like:
service = new MicroServiceVertxEBProxy(vertx, MicroService.ADDRESS);
service.execute()
In order to address this we should have a better generated proxy, for example it should be usable as:
service = new MicroServiceVertxEBProxy(vertx, MicroService.ADDRESS);
service
.execute()
.call(deliveryOptions -> { ... })
Here in the optional argument of call, one can capture the request, (say we're on vertx-web) and add the required headers, e.g.:
.call(deliveryOptions -> deliveryOptions.addHeader("auth-token", ctx.user().get("id_token")))
In order to achive this we would need some abstract proxy class:
public abstract AbstractVertxEBProxy {
private Vertx _vertx;
private String _address;
private DeliveryOptions _options;
private boolean closed;
public MicroServiceVertxEBProxy(Vertx vertx, String address) {
this(vertx, address, null);
}
public MicroServiceVertxEBProxy(Vertx vertx, String address, DeliveryOptions options) {
this._vertx = vertx;
this._address = address;
this._options = options;
try {
this._vertx.eventBus().registerDefaultCodec(ServiceException.class, new ServiceExceptionMessageCodec());
} catch (IllegalStateException ex) {
}
}
public final class Caller<T> {
private final String _action;
private final JsonObject _json;
private final io.vertx.core.Future<T> _future;
private Caller(io.vertx.core.Future<T> future) {
this._action = null;
this._future = future;
this._json = null;
}
private Caller(String _action, JsonObject _json) {
this._action = _action;
this._json = _json;
this._future = null;
}
public Future<T> call() {
return call(null);
}
public Future<T> call(Consumer<DeliveryOptions> postage) {
if (_action == null) {
return _future;
}
DeliveryOptions _deliveryOptions = (_options != null) ? new DeliveryOptions(_options) : new DeliveryOptions();
if (postage != null) {
try {
postage.accept(_deliveryOptions);
} catch (RuntimeException e) {
return Future.failedFuture(e);
}
}
MultiMap headers = _deliveryOptions.getHeaders();
if (headers == null) {
_deliveryOptions.addHeader("action", _action);
} else {
_deliveryOptions.getHeaders().set("action", _action);
}
return _vertx.eventBus().<T>request(_address, _json, _deliveryOptions)
.map(msg -> msg.body());
}
}
}
Then the generator would generate the following code:
// for each method in the @ProxyGen interface
//@Override
public Caller<String> method_name() { // <-- note Caller instead of `Future`
if (closed) return new Caller<>(io.vertx.core.Future.failedFuture("Proxy is closed"));
// encoding to JSON as usual...
// ...
return new Caller<>("execute", _json);
}
With this approach we can now annotate the message with the headers we wish.
Extra helpers could be added. Like in the example above, we could have a helper just for passing the auth-token as:
service = new MicroServiceVertxEBProxy(vertx, MicroService.ADDRESS);
service
.execute()
.authorizeAndCall(ctx.user().get("id_token"))