Search code examples
springrest-clientspring-resthttp-verbshttp-options-method

How to send HTTP OPTIONS request with body using Spring rest template?


I am trying to call a RESTfull web service resource, this resource is provided by a third party, the resource is exposed with OPTIONS http verb.

To integrate with the service, I should send a request with a specific body, which identities by a provider, but when I did that I got a bad request. After that I trace my code then I recognized that the body of the request is ignored by rest template based on the below code:

if ("POST".equals(httpMethod) || "PUT".equals(httpMethod) ||
            "PATCH".equals(httpMethod) || "DELETE".equals(httpMethod)) {
        connection.setDoOutput(true);
    }
    else {
        connection.setDoOutput(false);
    }

my question, is there a standard way to override this behavior or I should use another tool?


Solution

  • The code you've pasted is from

    SimpleClientHttpRequestFactory.prepareConnection(HttpURLConnection connection, String httpMethod)
    

    I know because I've debugged that code few hours ago. I had to do a HTTP GET with body using restTemplate. So I've extend SimpleClientHttpRequestFactory, override prepareConnection and create a new RestTemplate using the new factory.

    public class SimpleClientHttpRequestWithGetBodyFactory extends SimpleClientHttpRequestFactory {
    
    @Override
    protected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException {
        super.prepareConnection(connection, httpMethod);
        if ("GET".equals(httpMethod)) {
            connection.setDoOutput(true);
        }
    }
    

    }

    Create a new RestTemplate based on this factory

    new RestTemplate(new SimpleClientHttpRequestWithGetBodyFactory());
    

    A test to prove the solution is working using spring boot (@RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT))

    public class TestRestTemplateTests extends AbstractIntegrationTests {
    
    @Test
    public void testMethod() {
        RestTemplate restTemplate = new RestTemplate(new SimpleClientHttpRequestWithBodyForGetFactory());
    
        HttpEntity<String> requestEntity = new HttpEntity<>("expected body");
    
        ResponseEntity<String> responseEntity = restTemplate.exchange("http://localhost:18181/test", HttpMethod.GET, requestEntity, String.class);
        assertThat(responseEntity.getBody()).isEqualTo(requestEntity.getBody());
    }
    
    @Controller("/test")
    static class TestController {
    
        @RequestMapping
        public @ResponseBody  String testMethod(HttpServletRequest request) throws IOException {
            return request.getReader().readLine();
        }
    }
    

    }