@PatchMapping Spring Boot Example

In this tutorial, we will learn how to use @PatchMapping annotation in a Spring Boot application to handle HTTP PATCH requests.

@PatchMapping Annotation Overview

The PATCH HTTP method is used to update the resource partially and the @PatchMapping annotation is for mapping HTTP PATCH requests onto specific handler methods. 

Specifically, @PatchMapping is a composed annotation that acts as a shortcut for @RequestMapping(method = RequestMethod.PATCH).

@PatchMapping annotation takes the following optional elements 

consumes – Narrows the primary mapping by media types that can be consumed by the mapped handler.

headers  – The headers of the mapped request, narrowing the primary mapping. 

name – Assign a name to this mapping. 

params – The parameters of the mapped request, narrowing the primary mapping. 

path – The primary mapping expressed by this annotation. 

produces – Narrows the primary mapping by media types that can be produced by the mapped handler.

value – The primary mapping expressed by this annotation.

@PatchMapping Annotation Example

Let's build a simple Spring Boot project using IntelliJ IDEA to demonstrate the usage of @PatchMapping annotation. 

We will use Spring Data JPA to develop a repository layer and MySQL database at the backend. We will use the Postman client to test the REST API.

1. Create a Spring boot application

Spring Boot provides a web tool called Spring Initializer to bootstrap an application quickly. Just go to https://start.spring.io/ and generate a new spring boot project.

While generating the Spring Boot Project, make sure that you have added the following Maven dependencies:
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>com.mysql</groupId>
			<artifactId>mysql-connector-j</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>
Download the Spring Boot project as a zip file, unzip it, and import it into IntelliJ IDEA.

2. Configure MySQL Database

Since we’re using MySQL as our database, we need to configure the database URL, username, and password so that Spring can establish a connection with the database on startup. 

Open the src/main/resources/application.properties file and add the following properties to it:
spring.datasource.url=jdbc:mysql://localhost:3306/todo_management
spring.datasource.username=root
spring.datasource.password=Mysql@123

spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQLDialect

spring.jpa.hibernate.ddl-auto = update
Don’t forget to change the spring.datasource.username and spring.datasource.password as per your MySQL installation. Also, create a database named todo_management in MySQL before proceeding to the next section.

You don’t need to create any tables. The tables will automatically be created by Hibernate from the Todo entity that we will define in the next step. This is made possible by the property spring.jpa.hibernate.ddl-auto = update.

3. Create Model Layer - Todo JPA Entity

Let's create a class named Todo and add the following content to it:
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "todos")
public class Todo {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private String title;

    @Column(nullable = false)
    private String description;
    private boolean completed;
}
@Setter, @Getter, @NoArgsConstructor, and @AllArgsConstructor annotations are provided by the Lombok library and are used to generate getter and setter methods, a no-argument constructor, and an all-arguments constructor for the class.

The @Entity annotation indicates that the class is an entity in JPA, representing a table in a relational database. 

The @Table annotation specifies the name of the table that corresponds to this entity. In this case, the table name is "todos".

The @Id annotation marks the field id as the primary key for the entity. 

The @GeneratedValue annotation specifies the strategy for generating the primary key values. In this case, the GenerationType.IDENTITY strategy is used, which indicates that the database will automatically assign a unique identifier to each new entity.

The @Column annotation is used to specify the mapping of the field title to a column in the database table.

4. Create Repository Layer - TodoRepository

Now, we gonna create a Spring Data JPA repository to talk with the MySQL database. Let's create the following TodoRepository interface and add the following content to it:
import net.javaguides.todo.entity.Todo;
import org.springframework.data.jpa.repository.JpaRepository;

public interface TodoRepository extends JpaRepository<Todo, Long> {
}

5. Create DTO Class - TodoDto

Let's create TodoDto class to transfer the data between the client and server:
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class TodoDto {

    private Long id;
    private String title;
    private String description;
    private boolean completed;
}
Note that we will be using TodoDto class in the request and response of the REST APIs.

6. Custom Exception - ResourceNotFoundException

Let's create ResourceNotFoundException that we will create and throw whenever a resource with a given id does not exist in the database.
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

@ResponseStatus(value = HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException{

    public ResourceNotFoundException(String message) {
        super(message);
    }
}

7. Create Service Layer - TodoService interface and TodoServiceImpl class

TodoService interface

Let's create a TodoService interface and add the following code to it:
public interface TodoService {

    TodoDto completeTodo(Long id);
}

TodoServiceImpl class

Let's create a TodoServiceImpl class that implements the TodoService interface and its method:
import lombok.AllArgsConstructor;
import net.javaguides.todo.dto.TodoDto;

import net.javaguides.todo.exception.ResourceNotFoundException;
import net.javaguides.todo.repository.TodoRepository;
import net.javaguides.todo.service.TodoService;
import org.springframework.stereotype.Service;

@Service
@AllArgsConstructor
public class TodoServiceImpl implements TodoService {

    private TodoRepository todoRepository;

    @Override
    public TodoDto completeTodo(Long id) {

        Todo todo = todoRepository.findById(id)
                .orElseThrow(() -> new ResourceNotFoundException("Todo not found with id : " + id));

        todo.setCompleted(Boolean.TRUE);

        Todo updatedTodo = todoRepository.save(todo);

        return mapToTodoDto(updatedTodo);
    }

    private TodoDto mapToTodoDto(Todo todo){
        TodoDto todoDto = new TodoDto();
        todoDto.setId(todo.getId());
        todoDto.setTitle(todo.getTitle());
        todoDto.setDescription(todo.getDescription());
        todoDto.setCompleted(todo.isCompleted());
        return todoDto;
    }
}
Note that the completeTodo() method only updates the completed field (not a complete Todo object) value in a todos database table.

8. Controller Layer - TodoController

Let's create TodoController class and build Complete Todo REST API that handles HTTP PATCH requests:
import lombok.AllArgsConstructor;
import net.javaguides.todo.dto.TodoDto;
import net.javaguides.todo.service.TodoService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("api/todos")
@AllArgsConstructor
public class TodoController {

    private TodoService todoService;

    // Build Complete Todo REST API
    @PatchMapping("{id}/complete")
    public ResponseEntity<TodoDto> completeTodo(@PathVariable("id") Long todoId){
        TodoDto updatedTodo = todoService.completeTodo(todoId);
        return ResponseEntity.ok(updatedTodo);
    }
}
Note that the Complete Todo REST API updates the resource partially. In our case,  this REST API only updates the completed field (not a complete Todo object) value in a todos database table.

The @RestController annotation is used to indicate that this class is a REST controller, which means it handles incoming HTTP requests and returns the corresponding responses. 

The @RequestMapping annotation specifies the base URL path for all the request mappings defined within this controller.

The @AllArgsConstructor annotation is provided by the Lombok library and generates a constructor with arguments for the class.

The @PatchMapping annotation maps this method to the HTTP PATCH method for the base URL path "api/todos/{id}/complete".
    // Build Complete Todo REST API
    @PatchMapping("{id}/complete")
    public ResponseEntity<TodoDto> completeTodo(@PathVariable("id") Long todoId){
        TodoDto updatedTodo = todoService.completeTodo(todoId);
        return ResponseEntity.ok(updatedTodo);
    }
Finally, a ResponseEntity object is returned with the updated todo object and the HTTP status code HttpStatus.OK to the client.

9. Start Spring Boot Application and Test Patch REST API

Test Coplete Todo REST API:

Let's use Comple Todo REST API to Patch a todo from the database:

10. Conclusion

In conclusion, this blog post provided an example of using the @PatchMapping annotation in a Spring Boot application. 

The @PatchMapping annotation is used to handle HTTP PATACH requests and is commonly used for updating the resources partially in RESTful APIs. 

Comments