-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add new definitionType
parameter for @Client
annotation
#11278
Conversation
I personally don't think we should do this. It adds more complexity. |
The use-case of reusing the same interface for a client and a controller is valid. Maybe the property can be called |
I would say we add |
@graemerocher Perhaps it would be better to give this parameter another name. It is a bit strange to name the For example, |
sure |
f51fad4
to
dc8d058
Compare
definitionType
parameter for @Client
annotation
Is there anything that needs to be mirrored except for Consumes/Produces? We could also simply add RequestType and ResponseType annotations that alias to Consumes or Produces depending on use site. |
@yawkat In my opinion, adding one additional parameter is much easier than adding new annotations. New annotations are more likely to confuse users - when what should be used. My personal opinion is that adding new annotations is exactly the same complication of logic and understanding. And an additional parameter in an annotation is quite laconic and is perceived as a setting |
public boolean isClient() { | ||
return this == CLIENT; | ||
} | ||
|
||
public boolean isServer() { | ||
return this == SERVER; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these methods need javadoc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
if (accept.isEmpty()) { | ||
String[] consumesMediaType = context.stringValues(Consumes.class); | ||
String[] consumesMediaType = context.stringValues(definitionType.isClient() ? Consumes.class : Produces.class); | ||
if (ArrayUtils.isEmpty(consumesMediaType)) { | ||
acceptTypes = DEFAULT_ACCEPT_TYPES; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it is likely this default handling needs altering based on the definition type
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand what you're suggesting?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
perhaps it is ok
/** | ||
* The interface definition type. Use {@code DefinitionType.SERVER} type, if you want | ||
* to use controller interface to describe HTTP client. Use {@code DefinitionType.CLIENT} type, | ||
* if you want to use custom interface to describe HTTP client. | ||
* | ||
* @return The interface definition type | ||
* @since 4.8.0 | ||
*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/** | |
* The interface definition type. Use {@code DefinitionType.SERVER} type, if you want | |
* to use controller interface to describe HTTP client. Use {@code DefinitionType.CLIENT} type, | |
* if you want to use custom interface to describe HTTP client. | |
* | |
* @return The interface definition type | |
* @since 4.8.0 | |
*/ | |
/** | |
* The interface definition type. When set to {@link DefinitionType.SERVER} the {@link Produces} and {@link Consumes} | |
* definition evaluated for each method of the interface will be reversed . | |
* | |
* <p>Whilst not necessarily recommended, there are scenarios like testing where it is useful to share a common interface between client and server and use the | |
* interface to create a new client declarative client. The client typically needs to produce the content type accepted by the server and consume the content type | |
* produced by the server. In this arrangement using the interface directly will not result in the correct behaviour.</p> | |
* | |
* <p>In this scenario you can set {@link DefinitionType} to {@link DefinitionType.SERVER} which will ensure the requests sent by the client use the content type declared by the {@link Consumes} | |
* annotation of the interface and that responses use the content type declared by the {@link Produces}.</p> | |
* | |
* <p>The default behaviour is to use {@link DefinitionType.CLIENT} where the inverse of the above is true.</p> | |
* | |
* @return The interface definition type | |
* @since 4.8.0 | |
* @see Consumes | |
* @see Produces | |
*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you will need to add the imports when merging this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
03bed67
to
5d7fd77
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think a new annotation is "simpler" than a parameter on @Client
that magically switches around the meaning of method annotations at-a-distance. But this PR is a low maintenance commitment so I'm not opposed
BTW @altro3 you do not need to force-push your changes into a single commit each time, we will squash any commits when merging anyway. |
@yawkat Is this a bad habit? |
it makes it a bit more difficult to review individual changes that address code review |
* @see Produces | ||
*/ | ||
@NonNull | ||
DefinitionType definitionType() default DefinitionType.CLIENT; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you annotate this with @Experiemental
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
* | ||
* @since 4.8.0 | ||
*/ | ||
enum DefinitionType { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you annotate this with @Experiemental
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed. Sorry, again force pushed. Forgot
5d7fd77
to
c7a016f
Compare
Thanks for the contribution! |
This was asked in the Discord, and I was also interested in this question earlier: is it possible to use a single interface to describe the client and the controller? The feign library was invented for Spring (8-9 years ago), which later became part of Spring Cloud. And so, when I saw that Micronaut has built-in support for a single interface, I was happy, but it turned out that the client and controller do not support the single interface mode.
So, for now, the main problem, in my opinion, is the opposite perception of the Consumes and Produces annotations for the client and the controller. I added the
definitionType
parameter, which can be one of two values -CLIENT
(default) andSERVER
.SERVER
value means that you use server (controller) interface to describe http client endpoints.Perhaps there are some other significant differences between the interface for the controller and the client, but I do not know about them.
Why is this important: in general, it is quite common practice to make a microservice with 2 submodules - API and business logic, so that you can write all the endpoints and DTOs in the API module, and then simply inherit from the interface and thus get a ready-made HTTP client.
@graemerocher @yawkat @sdelamo @dstepanov