I am getting 400 Bad Request when I send a GET request to Rest Service from JUnit Test case. My request body should be text/plain (Content-Type: text/plain) and the response should be a ResponseEntity of type Employee.
I am not getting any error when I call request using Postman, but how I'm not able to make it pass using Spring Web Client methods.
I have an example for a POST REQUEST where almost similar test implementation passes, the difference is that in the request body I pass an entire object of Employee and in the test which fails is a text/plain. ( Last added)
I tried to understand why it doesn't work, but I couldn't figure out.
I also tried to change exchange Method with getForObject, getForEntity but it didn't work.
Full URL : http://localhost:8080/employee/find/lastName/
L.E.: IntelliJ hellps me by highlighting .exchange method and tells me that that method will respond with 400.
Controller
@RequestMapping (value = "/find/lastName", headers="Content-Type=text/plain", method = RequestMethod.GET)
public ResponseEntity<Employee> findEmployeeByLastName(@RequestBody String lastName) {
return EmployeeService.getEmployeeByLastName(lastName);
}
Service
public static ResponseEntity<Employee> getEmployeeByLastName(String lastName) {
return employees
.stream()
.filter(employee -> employee.getLastName().equals(lastName))
.findFirst()
.map(employee -> new ResponseEntity<>(employee, HttpStatus.OK))
.orElseThrow(() -> new ExmployeeResourceException("Not Found"));
}
JUnit Test
@Test
public void ShouldReturnEmployeeByUsingLastName() {
RestTemplate restTemplate = new RestTemplate();
String employeeLastName = "Doe";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.TEXT_PLAIN);
HttpEntity<String> request = new HttpEntity<>(employeeLastName, headers);
ResponseEntity<Employee> responseEntity =
restTemplate.exchange(
HOSTNAME ENDPOINT "find/lastName/",
HttpMethod.GET,
request,
Employee.class
);
}
Error log
22:12:28.619 [main] DEBUG org.springframework.web.client.RestTemplate - Writing [Doe] as "text/plain" using [org.springframework.http.converter.StringHttpMessageConverter@48075da3]
22:12:28.764 [main] DEBUG org.springframework.web.client.RestTemplate - GET request for "http://localhost:8080/employee/find/lastName/" resulted in 400 (null); invoking error handler
org.springframework.web.client.HttpClientErrorException: 400 null at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:63)
at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:700)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:653)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:613)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:531)
at com.endava.rest.EmployeeTests.ShouldReturnEmployeeByUsingLastName(EmployeeTests.java:90)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
Example of test which passes
@Test
public void ShouldBeAbleToCreateAnEmployee() {
RestTemplate restTemplate = new RestTemplate();
Integer id = 3;
String firstName = "Ionut";
String lastName = "Popescu";
Employee newEmployee = new Employee(id, firstName, lastName);
HttpEntity<Employee> httpEntity = new HttpEntity<>(newEmployee);
ResponseEntity<Employee> responseEntity =
restTemplate.exchange(
HOSTNAME ENDPOINT,
HttpMethod.POST,
httpEntity,
Employee.class
);
}
CodePudding user response:
My request have a body which is a text (string) that's why I added the Content-Type header.
The RestTemplate client doesn't support entities in GET requests. This is lack of support for body in GETs pretty common in clients, given those kinds of APIs are rare.
More info on RestTemplate specifically:
I assume you are using a
RestTemplatewith a defaultClientHttpRequestFactory. In this case, JDK'sHttpURLConnectionis the underlying HTTP client.HttpURLConnectiondoes not send a request body for GET requests; I've verified that using Wireshark.
If you really are stuck with RestTemplate, your alternative is to use a different ClientHttpRequestFactory. For instance:
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpUriRequest;
import org.springframework.http.HttpMethod;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
import java.net.URI;
class HttpComponentsClientHttpRequestFactoryForGetWithBody extends HttpComponentsClientHttpRequestFactory {
private static final class HttpGetRequestWithBody extends HttpEntityEnclosingRequestBase {
public HttpGetRequestWithBody(URI uri) { super.setURI(uri); }
@Override public String getMethod() { return HttpMethod.GET.name(); }
}
@Override
protected HttpUriRequest createHttpUriRequest(HttpMethod httpMethod, URI uri) {
if (HttpMethod.GET.equals(httpMethod)) {
return new HttpGetRequestWithBody(uri);
}
return super.createHttpUriRequest(httpMethod, uri);
}
}
Usage:
restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactoryForGetWithBody());
