Let’s take a use case, we need to fetch a company details by passing it’s company name in a GET Api url. We will get appropriate results as long as the company name doesn’t have any special characters, especially “;”, “/”, “?”, “:”, “@”, “=” and “&”
Why it breaks when we use ‘&’ ? The url gets broken because, ‘&’ is a reserved character for URL schemes. For URL, ‘&’ is used to separate the query parameters.
Eg. http://localhost:9000/companies?name=TVS&location=pune
Above url explains,
protocol : http
domain- localhost
port number : 9000
context-path : companies
query param name : name
query param value : TVS
query param name : location
query param value : pune
Here, “&” helps to identify each query params associated with the url.
Now, what if a company name has “&” and we want to search ? Let’s rewrite the url ?
http://localhost:9000/companies?name=TVS&Moto&tier=2&location=pune
protocol : http
domain- localhost
port number : 9000
context-path : companies
query param name : name
query param value : TVS
query param name : Moto
query param value : (empty)
query param name : location
query param value : pune
In this case, you API request param for ‘name’ will consider only “TVS” as the search value and not the “TVS&Moto”. This will lead to retuning incorrect results.
How to resolve this ?
Case1: Angular/Javascript
If you are using Angular/Javascript, use below way to encode your param value,
const companyName = encodeURIComponent(companyName);
Use this companyName in your query. It will encode “&” into “%26,” so your value is not treated as another query param name. So, “TVS%26Moto” is treated as single value which will be interpreted as “TVS&Moto” in your API endpoint.
Case2: Java
If you are invoking another API from your java, then use query params as below,
String url = "http://localhost:9000/companies?name={companyName}&location={location}
Map<String, String> params = new HashMap<>();
params.put("companyName","TVS&Moto");
params.put("location","pune");
ResponseEntity<Object> response = restTemplate.exchange(url, HttpMethod.GET, null, new ParameterizedTypeReference<>(){}, params);
Here, the restTemplate will encode the params values (It uses UriTempalteHandler.expand() which encodes each param values). So we don’t need to encode it explicitly.
Note: Do not use string.replace() to replace params values as below !
String url = "http://localhost:9000/companies?name=companyName&location=location
String encodedUrl =url.replace("companyName",URLEncoder.encode("TVS&Moto").replace("location","pune);
//encodedUrl = http://localhost:9000/companies?name=TVS%26Moto&location=pune
ResponseEntity<Object> response = restTemplate.exchange(url, HttpMethod.GET, null, new ParameterizedTypeReference<>(){}, null);
Even if above code looks good and we are sending encoded company name, the rest template will form the finla url as below
http://localhost:9000/companies?name=TVS%2526Moto&location=pune
Since we didn’t set it in params, the the entire url is encoded here so, it results in encoding % into %25. So, use params in order to get correct results.