In 1.0.0. I have following manual load balancer config:
micronaut:
http:
services:
myservice:
urls:
- http://localhost:8081
Now, for following operation:
public interface IOperation {
@Post("/op")
String op();
}
I declare following client:
@Client(id = "myservice", path = "/some/path")
public interface IClient extends IOperation {
}
What I expect is this code working:
@Singleton
class SomeBean {
@Inject protected IClient client;
public void doOp() {
client.op();
}
}
But it doesn't work, because the client does the request to http://localhost:8081/op instead of http://localhost:8081/some/path/op, because it ignores the @Client(path) annotation argument completely.
I've delved into the HttpClientIntroductionAdvice code, which is responsible for doing the request, and here's the culprit. This method creates a client with the proper contextPath, but only if there is not already defined a http client bean with the service name, and it is defined if you have configured it in yaml. Then the intercept() method uses this shared client, but it expects the contextPath is already set on the client and it doesn't set its own path.
I've done some workaround here:
// for default http clients taken from load balancer and not prepended with @Client(path) we need to prepend them manually here
if (getClientReturnedSharedClientInstance) {
String path = clientAnnotation.get("path", String.class).orElse(null);
if (path != null) {
uri = path + uri;
}
}
You have to specify the path via config:
micronaut:
http:
services:
myservice:
urls:
- http://localhost:8081
path: /some/path
The documentation clearly states:
This client configuration can be used in conjunction with the @Client annotation, either by injecting an HttpClient directly or use on a client interface. In any case, all other attributes on the annotation will be ignored other than the service id.
https://docs.micronaut.io/latest/guide/index.html#clientConfiguration
Maybe I understand something wrong here but does it mean that in a service I can only have one client with one hardcoded context path?
@l0co If you're creating a service with load balancing supplied by configuration, the context path will be the same for all clients. If you like you can edit the issue to ask for an improvement of the feature to support overriding the configuration with values from the annotation.
Note that you can work around this limitation by specifying the context path in your methods.
@Get("/some/path/hello")
OK, I've changed the title because it looks as a design flaw for me.
First thing is that I don't see a reason to ignore @Client(path) attribute if someone wants to use it. It also doesn't prevent from using configuration in the currently working way (if the path property is given in yaml, it can be used as is used now, if the path attribute is given on @Client it can override the path property from yaml).
The second thing is that's quite odd to have a service with only one context path possible by design. This is different that in other frameworks, like in spring boot + spring cloud AFAIR: service is a service (host + port), and I can have multiple endpoints in a single service, and I should be able to easily build clients to these endpoints.
I agree this should be improved and is confusing. Thanks for the feedback
I can confirm this works in 1.2.0.RC1.
:+1:
@jameskleeh is there any documentation I can use as reference to all configurations available? I just spent the whole afternoon with a problem because I could not find any reference to the "path" attribute in the config.
Most helpful comment
I agree this should be improved and is confusing. Thanks for the feedback