swagger-api / swagger-api/swagger-codegen

[JAVA][RestTemplate] Client: no way to turn off query params encoding by generated code

Open
#11,216 0 comments 0 reactions 0 assignees View on GitHub

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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.