-
Notifications
You must be signed in to change notification settings - Fork 1.9k
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
OkHttp and Feign produce "method GET must not have a request body." #1038
Comments
First, this can be achieved using a Using your example: Map<String, String> parameters = new LinkedHashMap<>();
parameters.add("sort", "id,desc");
parameters.add("size", "200000");
parameters.add("name", "feign");
parameters.add("version", "10.3.0");
@RequestLine("GET /api/1.0/search?{parameters}")
Results search(@QueryMap parameters); Before we look into any other areas you may be having trouble with, let's start there. Have you tried this? If so, can you please explain what behavior you saw? |
Hi Kevin, Yes, I checked the So basically I have class Controller : ConrollerApi {
override fun someEndpoint(request: SearchRequestDto, pageable: Pageable) {
}
} And I would not prefer either use "inconsistency way" where is my controller and api to that controller not inherited like this class Controller {
override fun someEndpoint(request: SearchRequestDto, pageable: Pageable) {
}
}
@Headers(value = ["Accept: application/json", "Content-Type: application/json"])
interface ControllerApi {
@RequestLine("GET /api/1.0/search?{parameters}")
fun someEndpoint(@QueryMap parameters: Map<String, String>)
} or "bad arguments for controller way" like this: class Controller : ConrollerApi {
override fun someEndpoint(parameters: Map<String, String>) {
}
} But I still can't understand why request parameters with expanders should be in forms parameters(in body of request when it's request parameters) |
That variable is named poorly. It deals with tracking request parameters and request body values and attempts to ensure that we don't create invalid requests. In your situation, this is what we call a red herring. Thank you for providing that additional context. I was getting tripped up in the code example. I'm not familiar with Kotlin. Let me see if I can recap this discussion and your issue. You have an Interface that you want to share between a Controller and the Feign Client. This interface has a method that takes two parameters, I suspect that you are seeing something like this:
and you want something like this:
If so, then I think I understand what you need. Let me look it over some more. |
You are exactly right about the issue.
But there is one important thing about this issue. Yes, I expected something like this and get the same from RequsetTemplate So, I think now you caught the point and have a complete understanding of the problem. And also sorry for Kotlin:) If you wish I could make a demo project with this problem on Java+Spring+Feign if you still have questions. Very thanks! |
Please feel free to reference on demo project of this issue. Just run FeignApiTest |
@kdavisk6 any updates on this bug? |
@scrat98 I've been reading your problem man, and even though I'm no expert on the field I have tried to carefully debug the Test class you've provided in the comment above. Long story short, looks like Feign uses this class in the middle of its processing, part of this method calls an encoder: In the end this encoder turns out to be the encoder you have used to construct your WebControllerApi in your test: However this encoder writes stuff on the body of the request, which is what you do not want: So I have passed a different encoder than yours, basically the same except it doesn't write stuff on the body: How I have discovered this:
If it doesn't help with your problem I think it can at least help people for further debugging, |
Please, look more carefully. I wrote about workaround and you did the same. The problem is not in encoder, the problem is while constructing RequestTemplate - it shouldn't have body param at all. See my explanation above |
@scrat98 As I see here all RequestTemplate.Factory#resolve implementations set a request body regardless of the method indeed as you said. I have pointed your project to a local feign-core with this modification: And it worked too. Maybe this is the solution you need ? Btw:
|
Of course, there are a lot of places where you could "fix" this. For example, I suggest But the actual right solution will be extend CollectionFormat to support those types of formats. And also this issue has another problem. I actually don't know which "http standards" feign supports, but imagine that someone uses feign with his own http protocol where GET method could accept body. Should feign handle this usecases? I don't know. That this why I can't make a pull request and need support from @kdavisk6 for example. |
Reviewing this thread, it appears that during contract parsing, the variables present are being incorrectly flagged as I am not against the proposed changes to |
#1144 should correct the original issue of Feign incorrectly identifying certain parameters are form parameters. However, the second issue, where query parameters are always named, remains. I'm not quite sure how to proceed there. I'm open to suggestions. |
I've considered a few other options but I think the best answer for this issue has been merged and released in #1144. With regards to the naming issue, I think that #1019 will provide the right balance of support and flexibility. I'm going to close this issue and ask that any additional comments be placed in #1019 |
Imagine that we have searchable api which accepts "request" and "pageable" like
/api/1.0/search?sort=id,desc&size=20000&name=feign&version=10.3.0
In that case I can't use "@QueryMap", because it should present only on one parameter.
This is our REST API interface:
This is our custom DTO definition:
Pageable is Spring commonly used interface.
These are the expanders that we are using to generate the final request:
The problem that we faced is that while using this API, Feign is unable to construct a proper QueryTemplate, since the CollectionFormat is supposed to be something like ?[key]=[value], e.g. key1={value1}&key2={value2}. However, we would like to omit having keys and just include already expanded values like ?{expanded-value}.
Therefore, if we do not follow the standart CollectionFormat ?[key]=[value], the QueryTemplate gets constructed with empty templateChunks, so the getVariables method returns empty array.
Then, in feign.Contract we could see this:
In our case when getVariables is empty, it will add our query parameters to form parameters and therefore to the body of RequestTemplate, which is not what we want.
When trying to run this request via the OkHttpClient, we will receive an exception that "method GET must not have a request body."
This behavior seems strange to me, since it basically violates the standards. And this is obviously not the behavior what I want when I generate the custom request line myself with expanders.
Maybe you could consider adding a simple condition to prevent adding any form params for the GET request like this?
I would love to hear any response of this, but please be aware that I cannot change the API that I am using and I have to stick with it.
The text was updated successfully, but these errors were encountered: