RestTemplate: How to send URL and query parameters together - java

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.

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"
*/

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

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*

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-

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)

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.

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

Related

Add query params after building the URIComponents

I am using a UriComponentsBuilder to create my GET request endpoint and it works fine.
But I am trying to make it reusable such that I can pass in as many request params and
path variables as I want without limiting it. This is fine for path variables since I
can pass as many params as I want as a map inside buildAndExpand.
But how could I do it for request param too? Please advice.
This is what I am currently doing but this is not reusable.
public Map get(String a, String b, String c, String d, String e) {
String url = "domain.com/get/{a}/{b}";
String endPoint = UriComponentsBuilder.fromHttpUrl(url)
.queryParam("c" ,c)
.queryParam("d" ,d)
.queryParam("e" ,e)
.buildAndExpand(
new HashMap<String, String>() {{
put("a", a);
put("b", b);
}}
).toUriString();
return restTemplate.getForEntity(endPoint, Map.class);
}
I want to instead pull out the endpoint creation as a separate method as follows.
private UriComponents getUriComponent(String url, Map<String, String> params) {
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url);
return builder.buildAndExpand(params);
}
This would work fine for the path params a and b.
But how can I take in an argument here for b,c,e too which are query params.
Or some other suggestions to keep it dynamic. So I can pass in 5 queryParam for one request
and 10 queryParam for another without having to rewrite the UriComponentsBuilder each time.
Please note that preferably, I do not want to modify the url to like the following for this.
String url = "domain.com/get/{a}/{b}?c={c}&d={d}&e={e}";
So, using UriComponentsBuilder you can add new parameters to the URL.
String old = UriComponentsBuilder.newInstance()
.scheme("http")
.host("localhost")
.queryParam("a", "b")
.build()
.toUriString();
// probably other method
String res = UriComponentsBuilder
.fromHttpUrl(old)
.queryParam("new", "new")
.build()
.toUriString();
System.out.println(res); // output: http://localhost?a=b&new=new
If you need to add params stored in a Map, create an instance of org.springframework.util.MultiValueMap and call queryParams or replaceQueryParams depending on your needs to add parameters or replace parameters.
// I've changed method signature to accept Map<String, List<String>>, but you can leave just String and wrap String to a singleton list
private UriComponents getUriComponent(String url, Map<String, List<String>> params) {
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url)
.queryParams(new LinkedMultiValueMap<>(params));
return builder.build();
}

RestTemplate POST with query parameter without request body

I am trying a POST method with RestTemplate. I need my request to have only 1 query parameter, without body (e.g. localhost:8080/predictions/init?date=xxxx).
My current code is the following :
String url = "http://localhost:8080/predictions/init";
String dateToGenerate = "xxxx";
MultiValueMap<String, String> headers = new LinkedMultiValueMap<String, String>();
Map map = new HashMap<String, String>();
map.put("Content-Type", "application/json");
headers.setAll(map);
Map req_payload = new HashMap();
req_payload.put("date", dateToGenerate);
HttpEntity<?> request = new HttpEntity<>(req_payload, headers);
restTemplateApi.postForEntity(url, request, String.class);
The side of the REST controller I'm trying to call is the following :
#PostMapping
#ResponseStatus(HttpStatus.OK)
public PredictionGenerated initializeOnePrediction(#RequestParam #NotEmpty String date) {
.............................
.............................
}
I'm currently receiving org.springframework.web.client.HttpClientErrorException: 400 null.
Any ideas?
If you have any many query param then set all in Multiple value Map as below.
MultiValueMap<String, String> param= new
LinkedMultiValueMap<String, String>();
param.put("date", datevalue);
Then create Http header add required content.
HttpHeaders headers = new HttpHeaders()
header.setContentType("application/json");
Create the URL as below.
URI url = UriComponentsBuilder.fromHttpUrl(base url)
.queryParams(param)
.build();
HttpEntity<?> request = new HttpEntity<>(req_payload,
headers);
restTemplateApi.postForEntity(url, request, String.class);

how i can pass parameters in restTemplate to controller's put method

I have a problem with passing parameters.
I have names in my income app and i want to update them by passing a parameters of new names from my rest app.
This is my code:
String url = "http://localhost:8084/rest/api/income/UpdateName/{oldName}/{newName}"; // the Url of the rest
Map<String, String> params = new HashMap<>();
params.put("oldName", oldName);
params.put("newName", newName);
Income income = new Income();
RestTemplate restTemplate = new RestTemplate();
restTemplate.put(url, income, params);
System.out.println(params);
}
This code is not working unfortunately, what can I do?
This is the put method in the controller :
#CrossOrigin
#GetMapping("/UpdateName/{oldName}/{clientName}") // view all incomes ..
public GeneralResponse viewAllIncome(#PathVariable("oldName") String oldName,#PathVariable("clientName") String clientName) {
return new GeneralResponse(incomeServiceTemplate.updateClientName(oldName,clientName));
}
The endpoint is GET not PUT, just append the parameters in the URL and call:
String url = "http://localhost:8084/rest/api/income/UpdateName/"+oldName+"/"+newName;
RestTemplate restTemplate = new RestTemplate();
restTemplate.getForObject(url, Income.class);
Or there's a better way, use uriComponentsBuilder. It takes care of url encoding:
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url)
.queryParam("oldName", oldName)
.queryParam("newName", newName);
restTemplate.getForEntity(builder.build().encode().toUri(), Income.class);

Make PUT call to external website using Rest Template

I'm currently trying to make a PUT call to my Gemfire Cache test enviroment
https://gemfire.docs.pivotal.io/95/geode/rest_apps/put_update_data.html
I've tried following a template like so
RestTemplate restTemplate = new RestTemplate();
String url = "http://localhost:8080/spring-rest/data/putdata/{id}/{name}";
Map<String, String> map = new HashMap<String, String>();
map.put("id", "100");
map.put("name", "Ram");
Address address = new Address("Dhananjaypur", "Varanasi","UP");
restTemplate.put(url, address, map);
}
Where in my case would it look something like this?
RestTemplate restTemplate = new RestTemplate();
String url = "gemfire.com/gemfire-api/v1/{region}/{key};
Map<String, String> map = new HashMap<String, String>();
map.put("region", "1");
map.put("key", "testKey");
restTemplate.put(url, "testStringtoPut", map);
}
This template leads into a 404 not found error for me,
can someone provide an insight on a proper method of doing this?
Try doing it this way, it should work
HttpEntity<String> request = new HttpEntity<String>(address.toString());
String url=http://localhost:8080/spring-rest/data/putdata/100/"Ram"
ResponseEntity <String> response= template.exchange(url,HttpMethod.PUT,request,String.class);

how to pass queries to a url in rest template without uri

I am trying to make a GET call to a url and I need to pass in queries to get the response i want.
I am using spring framework and using Rest template to make the calls.
I know i can manually do this way:
Uritemplate(url+name={name}...
but this is a pain. I need a easier way and the hash map will be generated dynamically
So how do i pass in a map to a url without using uri encoder?
String url = "example.com/search
Map<String, String> params = new HashMap<String, String>();
params.put("name", "john");
params.put("location", "africa");
public static ResponseEntity<String> callGetService(String url, Map<String, String> param) {
RestTemplate rest = new RestTemplate();
rest.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
HttpEntity<?> reqentity = new HttpEntity<Object>(headers);
ResponseEntity<String> resp = rest.exchange(url, HttpMethod.GET, reqentity, String.class);
System.out.println(resp);
return resp;
}
So url will end up like this example.com/search?name=john&location=africa
response: {name:john doe, love: football} --- tons of json data
You can use UriComponentsBuilder and UriComponents which facilitate making URIs
String url = "http://example.com/search";
MultiValueMap<String, String> params = new LinkedMultiValueMap<String, String>();
params.add("name", "john");
params.add("location", "africa");
UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl(url).queryParams(params).build();
System.out.println(uriComponents.toUri());
prints
http://example.com/search?name=john&location=africa
There are other options if you need to use URI variables for path segments.
Note that if you are sending an HTTP request, you need an valid URL. The HTTP URL schema is explained in the HTTP specification, here.
The UriComponentsBuilder provides methods to build all parts of the URL.

Categories