PUT and PATCH explanation

What is the use of PUT
Put is used to update the entire object and it is an idempotent, in our application when we refering the PUT resource then below assumptions will play a key role

  1. 1. You are referring to an entity.
  2. 2. The entity you are supplying is complete and its impact on entire object.

What is the use of PATCH
PATCH is used to update the specific column or field in the database and which is non-idempotent, in our application when we refering the PATCH resource then below assumptions will play a key role

  1. 1. You are referring to a single field update
  2. 2. No impact on entire object or entity.

Example lets say simply we have created a user using below fields using the POST HTTP request


                      { "username": "sadakhat", "email": "sadakhat@gmail.com" }
                    

If you want to modify this entity later, you choose between PUT and PATCH. A PUT might look like this:

                      ## PUT /users/1
                        {
                            "username": "sadakhat",
                            "email": "sadakhatali@gmail.com" // new email address
                        }
                    

You can accomplish the same using PATCH. That might look like this:

                      ## PATCH /users/1
                      {
                          "email": "sadakhatali@gmail.com"       // new email address
                      }
                    

You'll notice a difference right away between these two. The PUT included all of the parameters on this user, but PATCH only included the one that was being modified (email).

When using PUT, it is assumed that you are sending the complete entity, and that complete entity replaces any existing entity at that URI. In the above example, the PUT and PATCH accomplish the same goal: they both change this user's email address. But PUT handles it by replacing the entire entity, while PATCH only updates the fields that were supplied, leaving the others alone.

Since PUT requests include the entire entity, if you issue the same request repeatedly, it should always have the same outcome (the data you sent is now the entire data of the entity). Therefore PUT is idempotent.

Lets see an example

First, we need to create a simple SprintBoot and SprintDataJPA applicaiton using MySql, which can be created with the help of following tutorial Customer Registration on top of this we need to make changes to understand the PUT and PATCH difference.

First will refer the PUT HTTP request type, Inside the controller we have written a code to update the specific filed, as part of this we're passing entire object in the request body, please refer the below snippet. Which is not recommanded in case of single field update. Download the source code from below and understand the PUT HTTP request flow.


                    /**
                    * update a specific customer, in case of put mapping this method will get invoked.
                    *
                    * @param customerId customer id
                    * @param request customer request object
                    * @return response entity object
                    */
                   @PutMapping("/update/{customerId}")
                   public ResponseEntity<APIResponse> updateCustomer(@PathVariable long customerId, @RequestBody CustomerRequest request) {
                       return customerService.updateCustomerDetails(customerId, request);
                   }
                  

Implementation in the service class


                    /**
                    * This method is used to update the customer details into the database.
                    *
                    * @param customerId customer id
                    * @param request customer request object
                    * @return responseEntity object
                    */
                   @Override
                   public ResponseEntity<APIResponse> updateCustomerDetails(long customerId, CustomerRequest request) {
               
                       Optional<CustomerModel> modelOptional = customerRepository.findById(customerId);
                       if (modelOptional.isPresent()) {
                           CustomerModel model = modelOptional.get();
                           model.setCustomerName(request.getCustomerName());
                           model.setCustomerAge(request.getCustomerAge());
                           model.setCustomerMobileNumber(request.getCustomerMobileNumber());
                           model.setCustomerEmailAddress(request.getCustomerEmailAddress());
                           model.setCustomerAddress(request.getCustomerAddress());
                           model = customerRepository.save(model);
               
                           return ResponseEntity.ok(
                                   APIResponse.builder()
                                           .errorCode(SUCCESS_CODE)
                                           .errorMessage(SUCCESSFULLY_UPDATED)
                                           .data(modelToResponseMapper(model))
                                           .build()
                           );
                       } else {
                           return ResponseEntity.ok(
                                   APIResponse.builder()
                                           .errorCode(CUSTOMER_NOT_EXISTS_CODE)
                                           .errorMessage(CUSTOMER_NOT_EXISTS)
                                           .data(List.of())
                                           .build()
                           );
                       }
                   }
                  

Lets implement a PATCH HTTP request now

To implement a PATCH HTTP request, first we need to create a new enpoint in controller like below.


                    /**
                    * update a specific field from the entity, using PATCH
                    *
                    * @param customerId customer id
                    * @param customerAddress customer address object
                    * @return response entity object
                    */
                   @PatchMapping("/update/address/{customerId}")
                   public ResponseEntity<APIResponse> updateAddress(@PathVariable long customerId, @RequestBody CustomerAddress customerAddress) {
                       return customerService.updateCustomerAddress(customerId, customerAddress);
                   }
                  

Updated the new method in service and service Implementation class

                     ResponseEntity<APIResponse> updateCustomerAddress(long customerId, CustomerAddress customerAddress); // new method
                  


                    /**
                    * This method is used to update the address field using PATCH HTTP request type.
                    *
                    * @param customerId customer id
                    * @param customerAddress customer address
                    * @return responseEntity object
                    */
                   @Override
                   public ResponseEntity<APIResponse> updateCustomerAddress(long customerId, CustomerAddress customerAddress) {
                       Optional<CustomerModel> modelOptional = customerRepository.findById(customerId);
                       if (modelOptional.isPresent()) {
                           CustomerModel model = modelOptional.get();
                           model.setCustomerAddress(customerAddress.getCustomerAddress());
                           model = customerRepository.save(model);
               
                           return ResponseEntity.ok(
                                   APIResponse.builder()
                                           .errorCode(SUCCESS_CODE)
                                           .errorMessage(SUCCESSFULLY_UPDATED)
                                           .data(modelToResponseMapper(model))
                                           .build()
                           );
                       } else {
                           return ResponseEntity.ok(
                                   APIResponse.builder()
                                           .errorCode(CUSTOMER_NOT_EXISTS_CODE)
                                           .errorMessage(CUSTOMER_NOT_EXISTS)
                                           .data(List.of())
                                           .build()
                           );
                       }
                   }
                  

Created below CustomerAddress object

                    package com.sb.sdjpa.crud.request;

                    import lombok.*;

                    @Getter
                    @Setter
                    @NoArgsConstructor
                    @AllArgsConstructor
                    @ToString
                    @EqualsAndHashCode
                    @Builder(toBuilder = true)
                    public class CustomerAddress {
                        private String customerAddress;
                    }
                  

Testing through postman

Before we update the field, first will make a get call and check the data, refer below screenshot.


Now will make a postman call using PATCH HTTP request type and will update the address field, check below screenshot


Full source code is available in follwong GitHub repository: SpringBoot PUT and PATCH Differences