-
Notifications
You must be signed in to change notification settings - Fork 2.8k
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
Quarkus Rest empty @QueryParam is handled differently #44885
Comments
It seems the change is not in validation but in how the empty query param is treated I have another failing test on a similar case where |
THis started to fail on Nov 18 and was working on Nov 15 |
here is a new reproducer clearly showing that empty query params are now handled differently: |
/cc @FroMage (rest), @stuartwdouglas (rest) |
This change was intentional, and explained in #42468 (comment) If you have use-cases that require the old behaviour, let us know, because we could not think of any. |
Thanks for spotting that @FroMage! I had completely forgot about that one... |
@FroMage let's close this when this is in the migraition guide |
Thanks @FroMage @geoand @cescoffier |
@FroMage @geoand @cescoffier Think of this as a form of mutation that is submittet... null means no processing required here (ie leave it untouched)... empty string means delete it.. thats the logic that the system has implemented 😄 How this is totally broken with 3.18.x This also is a result of using generated Rest Clients. As the methods generated have all params, and this forces the developers to fill something in.. so a lot of nulls normally for all the optional params. The REST clients dont send nulls, but they do send empty strings |
I had a look at what initially triggered the issue. From what I could see, it wasn't related to strings and then the fix affected strings to improve consistency. I agree it's not exactly easy to find a consistent way of doing things but I must admit I'm a bit worried about this change for strings. |
Take these two examples: path?myQueryParam=&anotherParam=foo For me there is a big difference in those two urls, with the first having the intention of submitting a value for that param. So myQueryParam should not be null in both (and IMO any @default should only kick in on the second one) |
The original behaviour was mostly unintentional, non-specified, and not consistent. You can still obtain the information that the query included one key with no value from the Vert.x request. If there are multiple users who want to obtain this information, we could add a new API as a new feature to get that info, but so far I think this is the first time someone asks for that. |
Using that Vert.x request as a workaround might be easy enough. But finding all places, to use this workaround, that now breaks in 100's of endpoints will be a major pain here |
Sorry :( You could also turn these |
Or… perhaps you can write a request filter that turns |
Would it be possible with a config to enable legacy behavior and some kind of log message that we can look for and fix? I much rather fix the code correct than doing lots of workarounds.. and just make 3.19.x the cutoff? |
In which case do you expect a log message? Runtime based on the values passed? |
A flag to enable legacy behaviour, in itself, would not help us find all the places where this impacts us. Any time a param would be null and not empty string, it should emit a log message. " will be null with new behaviour on endpoint ". We would still need to analyse the exact impact on that endpoint, but it will likely reduce the number of endpoints greatly that we have to go over |
So let me rephrase this: are you looking for a build-time warning whenever we see a |
When we encounter query parameters like this: It could issue a message that myQueryParam is no longer an empty string but null.. at runtime yes Now, I think, there should be a flag to enable this, so its not spamming these messages at default |
@olivierbeltrandocintoo: find comments inline in bold:
Not for HTTP parameters, which REST is really standardised on. We do support it, but in addition to the HTTP semantics, not as a replacement for it. As for your primitive table, I am not sure if you meant In any case, deserialising Throwing a 400 when the type is incompatible (say |
This makes it possible for things like Kotlin Serialization to work properly. Fixes: quarkusio#44885
This makes it possible for things like Kotlin Serialization to work properly. Fixes: quarkusio#44885
This makes it possible for things like Kotlin Serialization to work properly. Fixes: quarkusio#44885
Closed by accident. |
I'm making progress on this. I have the non-parameter-container version ready already. Hopefully by the end of the week I can get parameter containers to also work. Perhaps. |
This is a bit all over the place. I thought I could afford to copy the code for |
Nevermind, thinking about this, this type makes no sense to support 😅 |
We're hitting the same issue here, but with the over-complication that we can't change the API because it's auto-generated by the OpenApi extension. Let me explain further this use case:
Where the UsageType is:
The autogenerated API is: @RegisterRestClient
@RegisterProvider(ApiExceptionMapper.class)
@Path("/api/rhsm-subscriptions/v1/capacity/products/{product_id}/{metric_id}")
public interface CapacityApi {
/**
* Fetch a capacity report for an account and product.
*
*/
@GET
@Produces({ "application/vnd.api+json" })
CapacityReportByMetricId getCapacityReportByMetricId(@PathParam("product_id") ProductId productId, @QueryParam("usage") UsageType usage) throws ApiException, ProcessingException;
} We use a custom param converter provider (see implementation here) but in Quarkus, this converter is not even called because of this line.
Note that I don't follow how a query param that always returns null regardless if it was unset or empty goes in the direction of being more consistent... (I didn't follow all the conversation though), but unless there is a |
Thanks @Sgitario, I had not thought about openapi generation and custom parameter converters that actually do support empty values. I was working hard to complete support for the Now, given what you said, I'm inclined to propose a different strategy:
The problem is that this will likely have to wait for my return in three weeks :-/ WDYT @geoand ? |
I am not sure this is a good thing to do TBH as I believe it will lead to even more confusion |
The way I see it, we should just include the new API when we have it (the sooner the better) in a next release of 3.20 LTS and tell people that really rely on the old (undocumented) behavior to wait |
I see your point. That's still a possibility. However, I don't know how we can deal with openapi generators, it's likely they won't be able to target this new API. Although it depends on whether openapi can distinguish element types and whether they allow for empty values or not. I used to think only With the current behaviour, and even the addition of the
|
I don't see a way to please everyone to be honest and I am -1 for causing even more confusion by flip-flopping |
@FroMage many thanks for the explanation about what originally motivated the changes. I reverted the changes where we switched this API to Quarkus, so our team can wait for a fix for 3 weeks (also I'm happy to help here).
@geoand since the original behaviour changed and there are no alternatives, I see this like a major regression issue. Note that many users might have not noticed this yet, but expect query params to be treated like null and empty values differently. |
…tly to swatch-contracts" (#4310) This reverts commit 2859248. Jira issue: SWATCH-3419 ## Description We're reverting the changes in #4292 because Quarkus does not distinguish between empty and null. This issue was introduced in Quarkus 3.18 and reported by quarkusio/quarkus#44885. Note that before reverting the changes, I tried to make this query param optional, but the openapi does not generate it as optional. Other solutions imply to use the raw request param to check what was the original query value (either unset or empty), but I see this solution as flaky/workaround (since there are many query types affected). Let's wait for what is the reply from Quarkus about this issue, since they seem to be keen to not revert what caused the issue). ## Testing Regression testing.
But there will be soon.
I'm sympathetic to that, but we also had users that expected the exact opposite (which is why we changed it). The fact is that the old behavior was an emergent property of the implementation, not something that was thought out or specified. |
Even when it was not thought or specified like this, it's how it was working before and how users have been using Quarkus so far.
Changing that, it's about forcing users/devs to start using optionals (the ones that noticed this critical change in behaviour) and it's against the consistency and stability :/ |
There are workarounds, currently. We've documented one here: #44885 (comment)
I assume you mean
I'm not sure what you mean about optionals here, but I don't think it's the |
I am sympathetic to that, though I suppose it depends a bit on how this can be adapted for OpenAPI generators, perhaps @phillip-kruger knows if in open-api we can detect that some query parameter types allow for an empty value or not (as opposed to an absent state). I would rather do as you suggest and move on from the previous behaviour. But I'm genuinely surprised by the number of reactions to this change. I did not expect that. I also did not expect that some parameter converters allowed for empty values. So, I'm a bit torn between both options. And when torn, I would tend to trust @geoand's opinion. Who knows, perhaps when I come back in three weeks we'll even have a clear path forward :) |
I undestood from the thread, that another solution was to start using java.lang.Optional for the query parameters that needed to differentiate between null and empty. But say optionals, or say implement something like this: #44885 (comment). It's forcing users for an implementation change that they might not even be aware of that this changed. |
Same! |
/cc @MikeEdgar |
Ah OK. Well, that's the new You do need a new API, but on the other hand, the previous behaviour:
|
Describe the bug
I initially discovered this in code.quarkus unit tests. For example when using
?a=
with a a List, the list size is not 0 while it was 1 before (with""
) as content.Same with String, before it was an empty string, not it's not defined.
Expected behavior
not sure but we need to clarify if it's an expected change
Actual behavior
it assumes
?a=
is the same as?
How to Reproduce?
reproducer-validation.zip
This reproducer works on 3.17
Output of
uname -a
orver
No response
Output of
java -version
No response
Quarkus version or git rev
main (3.18)
Build tool (ie. output of
mvnw --version
orgradlew --version
)No response
Additional information
No response
The text was updated successfully, but these errors were encountered: