2

I need to send a GET request with a json body in java/spring boot. I'm aware of the advice against it, however I have to do it this was for a couple of reasons: 1. The 3rd party API I'm using only allows GET requests, so POST is not an option. 2. I need to pass an extremely large parameter in the body (a comma separated list of about 8-10k characters) so tacking query params onto the url is not an option either.

I've tried a few different things:

  1. apache HttpClient from here: Send content body with HTTP GET Request in Java. This gave some error straight from the API itself about a bad key.

  2. URIComponentsBuilder from here: Spring RestTemplate GET with parameters. This just tacked the params onto the url, which as I explained before is not an option.

  3. restTemplate.exchange. This seemed the most straightforward, but the object wouldn't pass: https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/client/RestTemplate.html#exchange-java.lang.String-org.springframework.http.HttpMethod-org.springframework.http.HttpEntity-java.lang.Class-java.util.Map-

as well as probably another thing or two that I've forgotten about.

Here is what I'm talking about in Postman. I need to be able to pass both of the parameters given here. It works fine if run through Postman, but I can't figure it out in Java/Spring Boot.

Here is a code snippet from the restTemplate.exchange attempt:

public String makeMMSICall(String uri, List<String> MMSIBatchList, HashMap<String, String> headersList) {
    ResponseEntity<String> result = null;
    try {
        RestTemplate restTemplate = new RestTemplate();

        HttpHeaders headers = new HttpHeaders();
        for (String key : headersList.keySet()) {
            headers.add(key, headersList.get(key));
        }

        Map<String, String> params = new HashMap<String, String>();
        params.put("mmsi", String.join(",", MMSIBatchList));
        params.put("limit", mmsiBatchSize);

        HttpEntity<?> entity = new HttpEntity<>(headers);
        result = restTemplate.exchange(uri, HttpMethod.GET, entity, String.class, params);

        System.out.println(result.getBody());

    } catch (RestClientException e) {
        LOGGER.error("Exception in makeGetHTTPCall :" + e.getMessage());
        throw e;
    } catch (Exception e) {
        LOGGER.error("Exception in makeGetHTTPCall :" + e.getMessage());
        throw e;
    }
    return result.getBody();
}

Thanks for helping!

bgasdf12
  • 21
  • 1
  • 5
  • As you stated, sending a request body with a GET operation is not recommended. But what did the logs say when you tried restTemplate.exchange ? Are you sure you used correct syntax? If you could provide some logs and code, it would be more helpful. – Pajala Jan 13 '20 at 20:17
  • I added a code snippet from my attempt with restTemplate.exchange. The logs showed nothing out of the ordinary except for the API result one would expect from a default call to the API with no parameters. – bgasdf12 Jan 13 '20 at 20:34
  • GET requests do not contain a body. You can not do what you are attempting to do. Use POST, PUT or some other method that accepts a body. – DwB Jan 13 '20 at 20:34
  • As I stated in the question body, POST/PUT is not an option due to API restrictions. I know this is possible, since Postman is able to do it AND there are many other questions acknowledging that it is possible but advising against it whenever you can like here: https://stackoverflow.com/questions/978061/http-get-with-request-body?rq=1. I can't avoid it at this point. – bgasdf12 Jan 13 '20 at 20:41

2 Answers2

1

You can try java.net.HttpUrlConnection, it works for me but indeed I normally use a POST

HttpURLConnection connection = null;
BufferedReader reader = null;
String payload = "body";

try {

    URL url = new URL("url endpoint");

    if (url.getProtocol().equalsIgnoreCase("https")) {
        connection = (HttpsURLConnection) url.openConnection();
    } else {
        connection = (HttpURLConnection) url.openConnection();
    }
    //  Set connection properties
    connection.setRequestMethod(method); // get or post
    connection.setReadTimeout(3 * 1000);
    connection.setDoOutput(true);
    connection.setUseCaches(false);        

    if (payload != null) {
        OutputStream os = connection.getOutputStream();

        os.write(payload.getBytes(StandardCharsets.UTF_8));

        os.flush();
        os.close();
    }

    int responseCode = connection.getResponseCode();
}
baitmbarek
  • 2,252
  • 4
  • 15
  • 26
Beppe C
  • 4,511
  • 1
  • 5
  • 23
  • how does one add headers to this? the API I'm using requires a bearer token in the header. – bgasdf12 Jan 13 '20 at 20:35
  • Can use the following: `connection.setRequestProperty("Authorization", "token");` – Beppe C Jan 13 '20 at 20:54
  • With Java 8 ```String basicAuth = Base64.getEncoder().encodeToString((username+":"+password).getBytes(StandardCharsets.UTF_8)); httpConn.setRequestProperty ("Authorization", "Basic "+basicAuth);``` – g7p Jan 13 '20 at 21:16
-1

Try creating a new custom RequestFactory. Similar to get request with body

  • So the idea would be to add a class like this RequestFactory and then call RequestFactory.getRestTemplate instead of new RestTemplate()? – bgasdf12 Jan 13 '20 at 20:38
  • Yes, you can look into this demo as well https://github.com/mhshimul/spring-demo – ROHIT KANDIMALLA Jan 13 '20 at 20:55
  • 1
    I modified code from the demo to suit my purposes, but it did not work. The API still returned the default response when it does not receive any parameters. – bgasdf12 Jan 13 '20 at 21:30