7

I am trying to achieve same thing as this: How to use query parameter represented as JSON with Spring RestTemplate?, sending JSON string as a URL parameter in restTemplate.exchange().

The accepted answer mentions that sending JSON object as request parameter is generally not a good idea since you will probably face problem with curly brackets inside JSON. That is exactly what is happening when I am trying to make a GET call to an API. Since this is an API from another system, I cannot ask them to change the format and will have to call the GET endpoint, passing JSON as parameter. How can I achieve this in restTemplate.exchange() call?

Note: The mentioned related question does not guide on how to overcome this problem and I do not have enough reputation to comment on it to ask the author of the answer.

Community
  • 1
  • 1
user87407
  • 647
  • 3
  • 7
  • 24
  • And what's the problem with the response to the linked question? What is your code? What exact and complete error do you have? – JB Nizet Apr 06 '17 at 10:41
  • The error I get is: `java.lang.IllegalArgumentException: Not enough variable values available to expand '"size"'`. The json looks like this: `{"size":10000,"query":{"filtered":{"filter":{"term":{"run_id":"a5fc0cdb-0bce-4071-a850-77d181c0811d"}}}}}` – user87407 Apr 06 '17 at 10:46
  • The linked question only shows how to get JSON from an object, not how to use it in `exchange()` to avoid the error I mentioned above. – user87407 Apr 06 '17 at 10:50
  • If you want help with your code, post your code. And yes, it does show how to build a URL with parameter values. – JB Nizet Apr 06 '17 at 10:50
  • @JBNizet: I see.. I got it working by sending URI instead of String. Thanks! – user87407 Apr 06 '17 at 12:46

3 Answers3

16

Answering my own question. While it is a bad idea to pass JSON like this in a query/url parameter, there is a workaround as suggested here: https://jira.spring.io/browse/SPR-9220?focusedCommentId=76760&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-76760.
Replicating the code here in case this link goes dead:

String url = "http://localhost:8983/solr/select?wt=json&indent=true&fl=*&q=*:*&fq={!geofilt}&sfield=venue_location&pt=28.0674,-80.5595&d=25";
URI uri = UriComponentsBuilder.fromUriString(url).build().encode().toUri();

System.out.println(uri);
// http://localhost:8983/solr/select?wt=json&indent=true&fl=*&q=*:*&fq=%7B!geofilt%7D&sfield=venue_location&pt=28.0674,-80.5595&d=25

Basically, instead of passing url having JSON query/url parameters as a string, pass it as a URI. Then call exchange method as before, but with URI instead of String:

restTemplate.exchange(uri, HttpMethod.GET, requestEntity, String.class)
user87407
  • 647
  • 3
  • 7
  • 24
  • 2
    Thank you for your solution, passing an URI works like a charm! In my case, I need to pass some params: `UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(url); URI uri = builder.build().expand(params).encode().toUri(); restTemplate.getForObject(uri, String.class);` – dhqvinh May 03 '17 at 03:19
1

If this is 3rd party API and you cannot control or change JSON processing on backend side - there is no solution. Even if you will encode with URLEncoder - there is no guarantee that API backend would process such request correctly.

Alex Chernyshev
  • 1,719
  • 9
  • 11
0

You can use URLEncoder class to encode the URL in exchange method, e.g.:

String url = "http://www.yoursite.com/api?param={\"some_key\":\"some_value\"}";
System.out.println(URLEncoder.encode(url, StandardCharsets.UTF_8.name()));

This will encode the characters (like braces and double quotes) and server then will decode it back to json.

Darshan Mehta
  • 30,102
  • 11
  • 68
  • 102
  • 3
    I tried this. But `exchange` method ends up adding another encoding on top of this encoding, basically replacing all the `%` by `%25`. Hence, what server gets after decoding is another encoded string. – user87407 Apr 06 '17 at 10:43
  • What if you send the request without encoding? Do you get 4xx or 5xx in return? – Darshan Mehta Apr 06 '17 at 10:46
  • The error I get is: `java.lang.IllegalArgumentException: Not enough variable values available to expand '"size"'`. The json looks like this: `{"size":10000,"query":{"filtered":{"filter":{"term":{"run_id":"a5fc0cdb-0bce-4071-a850-77d181c0811d"}}}}}` – user87407 Apr 06 '17 at 10:47
  • So, I assume it is coming back from server (possibly 500 error)? If yes, could you post the code for `exchange` method? – Darshan Mehta Apr 06 '17 at 10:57
  • @ Darshan Mehta: No, the exception is thrown while building the URL, even before making the network call. I will add my code shortly. – user87407 Apr 06 '17 at 11:15
  • Looks like you are trying to query elasticsearch, why not use Search API then ;) https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-body.html – Darshan Mehta Apr 06 '17 at 11:19