swagger-api / swagger-api/swagger-codegen
[JAVA][RestTemplate] Client: no way to turn off query params encoding by generated code
Nobody has claimed this yet.
- Dominant language
- Mustache
- Stars
- 17.8k
- Forks
- 6k
- PR merge metrics
- No merged PRs in 30d
Description
Description
I am using swagger-codegen to generate a HTTP client for the 3rd party API. Some endpoints of that API return links with query params that should be followed to proceed with the next step. One of the query params value looks like this: someText%2FsomeOtherText.
The problem: when this query param value is passed to the generated HTTP client, it encodes it to someText%252FsomeOtherText (it assumes that % character should be encoded, so it is replaced with %25), so the wrong value is sent.
If the query param value is decoded before passing to the generated HTTP client (so someText/someOtherText), the client code under the hood treats / as a character that shouldn't be encoded, so the decoded value (someText/someOtherText) is passed further which is a wrong value as well.
Swagger-codegen version
3.0.25
Command line used for generation
Code generation is done via swagger-codegen-maven-plugin v.3.0.25 with such a params:
- language: java
- dateLibrary: java8
- java8: true
- useTags: true
- generateForOpenFeign: true
- library: resttemplate
Java 11 and Spring Boot v.2.5.3 are used within the project.
Suggest a fix/enhancement
I debugged the generated code and found the cause of such a behavior: swagger-codegen generates ApiClient class for such params (Java and RestTemplate) - here is the link to the mustache template of this class and this class has such a line of code:
final BodyBuilder requestBuilder = RequestEntity.method(method, builder.build().toUri());
Under the hood builder.build() method looks like this (builder is org.springframework.web.util.UriComponentsBuilder):
public UriComponents build() {
return build(false);
}
public UriComponents build(boolean encoded) {
...
So the generated line of code explicitly says that the content is not encoded via calling builder.build(). That's why on calling .toUri() method for org.springframework.web.util.HierarchicalUriComponents triggers the following code:
@Override
public URI toUri() {
try {
if (this.encodeState.isEncoded()) {
return new URI(toUriString());
}
else {
String path = getPath();
if (StringUtils.hasLength(path) && path.charAt(0) != PATH_DELIMITER) {
// Only prefix the path delimiter if something exists before it
if (getScheme() != null || getUserInfo() != null || getHost() != null || getPort() != -1) {
path = PATH_DELIMITER + path;
}
}
return new URI(getScheme(), getUserInfo(), getHost(), getPort(), path, getQuery(), getFragment());
}
}
catch (URISyntaxException ex) {
throw new IllegalStateException("Could not create URI object: " + ex.getMessage(), ex);
}
}
and, as we can see, since encodeState.isEncoded() is false, new URI(getScheme(), getUserInfo(), getHost(), getPort(), path, getQuery(), getFragment()) line is executed.
Under the hood, java.net.URI for this very constructor does encoding of some characters within query params.
The fix to this case is pretty simple and without breaking changes: within ApiClient class introduce a boolean class level property (let's call it encodingParamsDisabled for now) with the default value as false that will be passed to builder.build() method like this:
final BodyBuilder requestBuilder = RequestEntity.method(method, builder.build(encodingParamsDisabled).toUri());
Also, ApiClient class should have getter and setter methods for this new property to provide an API to configure it (so, to change it to true if needed).
I can create a PR by changing ApiClient mustache template file if you think it's something that is worth implementing.
Thanks and waiting for some feedback in terms of this.
Have fun =)
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with modules/swagger-codegen/src/main/resources/Java/libraries/resttemplate/ApiClient.mustache and inspect the request construction around builder.build(). Check how the generated ApiClient is configured and verify the proposed encoding option with a generated RestTemplate client using a query value containing an existing percent-encoded sequence. Done means the option is configurable and the generated request preserves the intended query value.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, spring
- Domain
- api, tooling
- Issue type
- Feature
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 35/100