In this article we will show you how to perform a PUT request in Spring using RestTemplate. We will take you through a simple integration test example to be able to test a PUT endpoint in a Spring Boot application.
Let’s start!
Setup
For the examples shown throughout this article, we will be using the same codebase we’ve shown in our previous Spring articles. You can see the latest version in our article “Exception Handling in Spring Rest Services in Java”.
In this article will look at our PUT endpoint only, and write an integration test for it. Our PUT endpoint looks like this:
@PutMapping(value = "/{id}", consumes = { MediaType.APPLICATION_JSON_VALUE })
ResponseEntity<String> updateCustomer(@PathVariable("id") Long id, @RequestBody Customer customer) {
return repository.update(id, customer)
.onSuccessDo(e -> ResponseEntity.noContent().build())
.onFailureDo(e -> {
if (e.exception() instanceof CustomerNotFound) {
return ResponseEntity.notFound().build();
} else {
return ResponseEntity.internalServerError().build();
}
}).response();
}
As you can see in this example, we are using a custom Either
monad to handle the responses, but for the purpose of this article you won’t have to worry about implementation details. Integration testing is a kind of black box test, we only care about the response, so the internals of the service should be completely opaque for the purposes of testing.
One more thing you’ll need in your application to be able to test it, is the Spring Boot test dependencies. You can import them by importing the Spring Boot starter test package in your build.gradle
file:
dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
implementation("org.springframework.boot:spring-boot-starter-web")
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
You will also notice that we are not specifying the version in our dependency import, this is because we have previously defined the Spring Boot version in our plugins
section:
plugins {
id 'java'
id 'org.springframework.boot' version '2.7.6'
id 'io.spring.dependency-management' version '1.0.15.RELEASE'
}
Now that we have the very basics of our Spring Boot application, we can now start with out test. If for any reason you need help to set up your initial application, you can check our article “How to Bootstrap a Spring Boot Application”.
Let’s start looking at our integration test then!
Test PUT Request in Spring
TestRestTemplate does not have an exact equivalent to getForEntity
or postForEntity
methods we saw in our previous articles. There is a put
method, although it’s difficult to test with it because it’s a void
method. This means that asserting the response cannot be done in our integration test.
Therefore, we are going to use exchange
method in our integration test. Let’s see how it works!
Using Exchange method
The exchange
method allows us to easily test a PUT endpoint in our application by sending a simple PUT request in Spring.
First of all, we will create a test to make sure that updating a non-existing customer returns 404 (NOT_FOUND).
@Test
public void shouldReturn404WhenTryingToUpdateANonExistingCustomer() {
final Customer updated = new Customer(99L, "Rowan Atkinson", 53);
final ResponseEntity<Customer> response = template.exchange(
String.format("http://localhost:%d/api/customers/99", port),
HttpMethod.PUT,
new HttpEntity<>(updated),
Customer.class
);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);
}
Because we haven’t persisted any customer yet, we won’t be able to update a customer with the given ID and we get back a 404 response, as we anticipated.
Let’s test now our successful scenario, we are going to create a customer using POST first and then update it using PUT.
@Test
public void shouldReturn204ResponseAndUpdateCustomer() {
final Customer newCustomer = new Customer(99L, "Margaret McGuinness", 27);
template.postForEntity(String.format("http://localhost:%d/api/customers", port), newCustomer, String.class);
final Customer updated = new Customer(99L, "Rowan Atkinson", 53);
final ResponseEntity<Customer> response = template.exchange(
String.format("http://localhost:%d/api/customers/99", port),
HttpMethod.PUT,
new HttpEntity<>(updated),
Customer.class
);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT);
assertThat(response.getBody()).isNull();
}
In this case, if the customer was successfully updated, we receive a 204 (NO_CONTENT) response with empty (or null) body. As simple as this!
At the moment we support JSON format only, what if we wanted to support a different media type like XML? How would our PUT request in Spring look like?

Supporting headers
To be able to understand how to use this method, we are going to change our example slightly. We are going to modify our POST endpoint so it can consume either JSON or XML.
To achieve this, we’ll just have to add XML to the consumes
argument in our PutMapping
annotation:
@PutMapping(consumes = { MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE })
This means that, in order to test both JSON and XML responses, we’ll need to send a Content-Type
header in our test. Our existing test won’t need to change, as the default format will be JSON if we don’t specify a Content-Type
header in our test. Let’s see how can we send XML then!
@Test
public void shouldReturn204ResponseAndUpdateCustomerinXmlFormat() {
final Customer newCustomer = new Customer(99L, "Margaret McGuinness", 27);
template.postForEntity(String.format("http://localhost:%d/api/customers", port), newCustomer, String.class);
final HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", MediaType.APPLICATION_XML_VALUE);
final Customer updated = new Customer(99L, "Rowan Atkinson", 53);
final ResponseEntity<Customer> response = template.exchange(
String.format("http://localhost:%d/api/customers/99", port),
HttpMethod.PUT,
new HttpEntity<>(updated, headers),
Customer.class
);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT);
assertThat(response.getBody()).isNull();
}
You can notice how we’re now passing a headers object to our exchange
method in our test. To make it work it was very simple, we just needed to send Content-Type: application/xml
and add the media type to our controller, as we saw earlier.
This is very straightforward, isn’t it?
If you are interested in learning Spring in depth, we highly recommend the following books:
Conclusion
In this article we’ve learned how to write a simple integration test for a PUT request in Spring Boot. We’ve also seen how to support two different content types in our endpoints in a very easy manner.
This is all from us today! We hope you’ve found this article useful and easy to read.
Looking forward to seeing you with us very soon again! Please follow us if you want to subscribe to more of our content!
Thanks for reading us!
You must log in to post a comment.