1. Overview
In this tutorial, weβll examine two important HTTP methods, PUT and POST, that we frequently use within the REST architecture. Itβs no secret that developers sometimes struggle to choose between these two methods while designing a RESTful web service. Therefore, weβll address this issue with a simple implementation of a RESTful application in Spring Boot.
2. PUT vs POST Dilemma
In a typical REST architecture, a client sends requests in the form of HTTP methods to the server to create, retrieve, modify, or destroy resources. While we can use both PUT and POST to create resources, there are significant differences between them in terms of their intended applications.
According to the RFC 2616 standard, the POST method should be used to request that the server accept the enclosed entity as a subordinate of the existing resource identified by the Request-URI. This means the POST method call will create a child resource under a collection of resources.
Conversely, the PUT method should be used to request that the server store the enclosed entity under the provided Request-URI. If the Request-URI points to an existing resource on the server, the supplied entity will be considered a modified version of the existing resource. Therefore, the PUT method call will either create a new resource or update an existing one.
Another important difference between the methods is that PUT is an idempotent method, while POST isnβt. For instance, calling the PUT method multiple times will either create or update the same resource. In contrast, multiple POST requests will lead to the creation of the same resource multiple times.
3. Sample Application
To demonstrate the difference between PUT and POST, weβll create a simple RESTful web application using Spring Boot. The application will store the names and addresses of people.
3.1. Maven Dependencies
To begin with, we need to include the dependencies for Spring Web, Spring Data JPA, and the in-memory H2 database in our pom.xml file:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
3.2. Domain Entity and Repository Interface
Letβs start by creating the domain object first. For the address book, weβll define an Entity class called Address that weβll use to store the address information of individuals. For the sake of simplicity, weβll use three fields, name, city, and postalCode, for our Address entity:
@Entity
public class Address {
private @Id @GeneratedValue Long id;
private String name;
private String city;
private String postalCode;
// constructors, getters, and setters
}
The next step is to access the data from the database. For simplicity, weβll leverage Spring Data JPAβs JpaRepository. This will allow us to perform CRUD functionalities on the data without writing any additional code:
public interface AddressRepository extends JpaRepository<Address, Long> {
}
3.3. REST Controller
Finally, we need to define the API endpoints for our application. Weβll create a RestController that will consume HTTP requests from the client and send back the appropriate response.
Here, weβll define a @PostMapping for creating new addresses and storing them in the database, and a @PutMapping to update the content of the address book based on the request URI. If the URI isnβt found, it will create a new address and store it in the database:
@RestController
public class AddressController {
private final AddressRepository repository;
AddressController(AddressRepository repository) {
this.repository = repository;
}
@PostMapping("/addresses")
Address createNewAddress(@RequestBody Address newAddress) {
return repository.save(newAddress);
}
@PutMapping("/addresses/{id}")
Address replaceEmployee(@RequestBody Address newAddress, @PathVariable Long id) {
return repository.findById(id)
.map(address -> {
address.setCity(newAddress.getCity());
address.setPin(newAddress.getPostalCode());
return repository.save(address);
})
.orElseGet(() -> {
return repository.save(newAddress);
});
}
//additional methods omitted
}
3.4. cURL Requests
Now we can test our developed application by using cURL to send sample HTTP requests to our server.
For creating a new address, weβll enclose the data in JSON format and send it through a POST request:
curl -X POST --header 'Content-Type: application/json' \
-d '{ "name": "John Doe", "city": "Berlin", "postalCode": "10585" }' \
http://localhost:8080/addresses
Now letβs update the content of the address we created. Weβll send a PUT request using the id of that address in the URL. In this example, weβll update the city and the postalCode section of the address we just created. Weβll suppose it was saved with id=1:
curl -X PUT --header 'Content-Type: application/json' \
-d '{ "name": "John Doe", "city": "Frankfurt", "postalCode": "60306" }' \
http://localhost:8080/addresses/1
4. Conclusion
In this article, we discussed the conceptual differences between the HTTP methods PUT and POST. Additionally, we learned how these methods can be implemented using the Spring Boot framework for developing RESTful applications.
In conclusion, we should use the POST method to create a new resource, and the PUT method to update an existing resource.
