How to escape ‘&’ in REST GET Api call ?

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.