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 GET
s pretty common in clients, given those kinds of APIs are rare.
More info on RestTemplate
specifically:
I assume you are using a
RestTemplate
with a defaultClientHttpRequestFactory
. In this case, JDK'sHttpURLConnection
is the underlying HTTP client.HttpURLConnection
does 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());