RestTemplate: How to send URL and query parameters together

JavaResttemplateUrl ParametersQuery ParametersPath Parameter

Java Problem Overview


I am trying to pass path param and query params in a URL but I am getting a weird error. below is the code

    String url = "http://test.com/Services/rest/{id}/Identifier"
    Map<String, String> params = new HashMap<String, String>();
    params.put("id", "1234");
    UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(url)
    									.queryParam("name", "myName");
    String uriBuilder = builder.build().encode().toUriString();
    restTemplate.exchange(uriBuilder , HttpMethod.PUT, requestEntity,
					class_p, params);

and my url is becoming http://test.com/Services/rest/%7Bid%7D/Identifier?name=myName

what should I do to make it work. I am expecting http://test.com/Services/rest/{id}/Identifier?name=myName so that params will add id to the url

please suggest. thanks in Advance

Java Solutions


Solution 1 - Java

I would use buildAndExpand from UriComponentsBuilder to pass all types of URI parameters.

For example:

String url = "http://test.com/solarSystem/planets/{planet}/moons/{moon}";

// URI (URL) parameters
Map<String, String> urlParams = new HashMap<>();
urlParams.put("planet", "Mars");
urlParams.put("moon", "Phobos");

// Query parameters
UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(url)
		// Add query parameter
		.queryParam("firstName", "Mark")
		.queryParam("lastName", "Watney");

System.out.println(builder.buildAndExpand(urlParams).toUri());
/**
 * Console output:
 * http://test.com/solarSystem/planets/Mars/moons/Phobos?firstName=Mark&lastName=Watney
 */

restTemplate.exchange(builder.buildAndExpand(urlParams).toUri() , HttpMethod.PUT,
        requestEntity, class_p);

/**
 * Log entry:
 * org.springframework.web.client.RestTemplate Created PUT request for "http://test.com/solarSystem/planets/Mars/moons/Phobos?firstName=Mark&lastName=Watney"
 */

Solution 2 - Java

An issue with the answer from Michal Foksa is that it adds the query parameters first, and then expands the path variables. If query parameter contains parenthesis, e.g. {foobar}, this will cause an exception.

The safe way is to expand the path variables first, and then add the query parameters:

String url = "http://test.com/Services/rest/{id}/Identifier";
Map<String, String> params = new HashMap<String, String>();
params.put("id", "1234");
URI uri = UriComponentsBuilder.fromUriString(url)
        .buildAndExpand(params)
        .toUri();
uri = UriComponentsBuilder
        .fromUri(uri)
        .queryParam("name", "myName")
        .build()
        .toUri();
restTemplate.exchange(uri , HttpMethod.PUT, requestEntity, class_p);

Solution 3 - Java

One-liner using TestRestTemplate.exchange function with parameters map.

restTemplate.exchange("/someUrl?id={id}", HttpMethod.GET, reqEntity, respType, ["id": id])

The params map initialized like this is a groovy initializer*

Solution 4 - Java

String url = "http://test.com/Services/rest/{id}/Identifier";
Map<String, String> params = new HashMap<String, String>();
params.put("id", "1234");
URI uri = UriComponentsBuilder.fromUriString(url)
        .buildAndExpand(params)
        .toUri();
uri = UriComponentsBuilder
        .fromUri(uri)
        .queryParam("name", "myName")
        .build()
        .toUri();
restTemplate.exchange(uri , HttpMethod.PUT, requestEntity, class_p);

> The safe way is to expand the path variables first, and then add the query parameters:

For me this resulted in duplicated encoding, e.g. a space was decoded to %2520 (space -> %20 -> %25).

I solved it by:

String url = "http://test.com/Services/rest/{id}/Identifier";
Map<String, String> params = new HashMap<String, String>();
params.put("id", "1234");
UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUriString(url);
uriComponentsBuilder.uriVariables(params);
Uri uri = uriComponentsBuilder.queryParam("name", "myName");
        .build()
        .toUri();
restTemplate.exchange(uri , HttpMethod.PUT, requestEntity, class_p);

Essentially I am using uriComponentsBuilder.uriVariables(params); to add path parameters. The documentation says:

> ... In contrast to UriComponents.expand(Map) or buildAndExpand(Map), this method is useful when you need to supply URI variables without building the UriComponents instance just yet, or perhaps pre-expand some shared default values such as host and port. ...

Source: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/util/UriComponentsBuilder.html#uriVariables-java.util.Map-

Solution 5 - Java

Since version 5.3 you can use this API to do this.

RequestEntity.post(urlString, urlParam1, urlParam2).headers(...).body(requestBody);

> public static RequestEntity.BodyBuilder post(String uriTemplate, Object... uriVariables)
> Create an HTTP POST builder with the given string base uri template.

At the docs: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/RequestEntity.html#post-java.net.URI-

Or

template.exchange(..., uriVariables)

Solution 6 - Java

One simple way to do that is:

String url = "http://test.com/Services/rest/{id}/Identifier"

UriComponents uriComponents = UriComponentsBuilder.fromUriString(url).build();
uriComponents = uriComponents.expand(Collections.singletonMap("id", "1234"));

and then adds the query params.

Solution 7 - Java

Below is the working code, I had to pass two values in the respective placeholders while making the query parameter.

String queryParam = "Key=Project_{ProdjectCode}_IN_{AccountCode}"

Map<String, String> queryParamMap = new HashMap<>();
queryParamMap.put("ProjectCode","Project1");
queryParamMap.put("AccountCode","Account1");

UriComponents builder = UriComponentsBuilder.fromHttpUrl("http://myservice.com/accountsDetails").query(queryParam).buildAndExpand(queryParamMap);

restTemplate.exchange(builder.toUriString(), HttpMethod.GET,httpEntity,MyResponse.class);

Above code will make a GET call to url http://myservice.com/accountsDetails?Key=Project_Project1_IN_Account1

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionShivaView Question on Stackoverflow
Solution 1 - JavaMichal FoksaView Answer on Stackoverflow
Solution 2 - Javaholmis83View Answer on Stackoverflow
Solution 3 - JavaK. O.View Answer on Stackoverflow
Solution 4 - JavaSascha HaßlerView Answer on Stackoverflow
Solution 5 - JavaAlexander.IljushkinView Answer on Stackoverflow
Solution 6 - JavaAldo Fernando SaiaView Answer on Stackoverflow
Solution 7 - JavaSanjay BharwaniView Answer on Stackoverflow