82

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.

7 Answers 7

188

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"
 */
Sign up to request clarification or add additional context in comments.

1 Comment

But "UriComponentsBuilder" class is not available in Spring 3. is there any alternative solution for Spring 3?
22

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);

Comments

5

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*

1 Comment

have you tried with path variable .Here your example demonstrate with query param and question was raised with respect to path param.
3
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-

Comments

0

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

Comments

0

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)

Comments

-1

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.