'http POST request: curl and postman both succeeded but resttemplate gives 400 Bad Request

I'm trying to convert a curl (also proved working in postman) query to java resttemplate:

$ curl -X POST https://my.server/apiv2/login -k  -H 'Accept: application/json' -H 'Content-Type: application/json' -d '{"password":"forgetme","userName":"myname"}'
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   593  100   492  100   101   1817    373 --:--:-- --:--:-- --:--:--  2196{"token":"sometoken",...}

However, the following code gives 404 error

JSONObject payload = new JSONObject();
    payload.put("userName", this.serviceAccount);
    payload.put("password", this.password);

    HttpHeaders headers = new HttpHeaders();
    headers.add("Accept", MediaType.APPLICATION_JSON.toString());
    headers.add("Content-Type", MediaType.APPLICATION_JSON.toString());

    HttpEntity<String> entity = new HttpEntity<String>(payload.toString(), headers);
        
    ResponseEntity<Response> result =
        this.restTemplate.exchange(tokenUrl.toString(), HttpMethod.POST, entity, Response.class);

I verified that the url, user name, and password are all correct.

2022-05-14 04:04:03 [scheduling-1] ERROR  *** url =https://my.server/apiv2/login
2022-05-14 04:04:03 [scheduling-1] ERROR  *** entity = <{"password":"forgetme","userName":"myname"},[Accept:"application/json", Content-Type:"application/json"]>

The only thing which seems to be related is that in the entity, application/json is enclosed by double quotes and if I put double quotes in curl around application/json, the query would fail (no response at all.

If I change the entity construction code to

HttpEntity<JSONObject> entity = new HttpEntity<JSONObject>(payload, headers);

I will get 400 Bad Request exception

==================================================== I would not post this as an answer until I understand why. I managed to make it work by initializing the resttemplate as following:

HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
      requestFactory.setConnectTimeout(300000);
      requestFactory.setReadTimeout(300000);
      this.restTemplate = new RestTemplate(requestFactory);
      this.restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
      this.restTemplate.getMessageConverters().add(new FormHttpMessageConverter());
      this.restTemplate.setErrorHandler(new MyThrowErrorHandler());


public class MyThrowErrorHandler implements ResponseErrorHandler {
  @Override
  public boolean hasError(ClientHttpResponse response) throws IOException {
    return false;
  }

  @Override
  public void handleError(ClientHttpResponse response) throws IOException {

  }
}

I understand that it ignores exception but the query is actually successful and I've got the response as expected. So my question now is if it's indeed a BAD REQUEST, how the above extra code fixes the bad request.



Solution 1:[1]

In these kind of scenarios, you could try debugging payload. I use https://req.dothttp.dev/ to preview curl of the request.

replace url with https://req.dothttp.dev/https://my.server/apiv1/login and compare with working curl statement.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 cedric