Spring RestTemplate - GET, POST, PUT and DELETE Example

Let's first build CRUD REST APIs using Spring Boot, Spring Data JPA, and MySQL database and then we will see how to use RestTemplate class to invoke CRUD REST APIs.

1. Creating Spring Boot Project

There are many ways to create a Spring Boot application. The simplest way is to use Spring Initializr at http://start.spring.io/, which is an online Spring Boot application generator.

Next, add the following Maven dependencies to the Spring boot project:
		<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>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-validation</artifactId>
		</dependency>
		<dependency>
			<groupId>com.mysql</groupId>
			<artifactId>mysql-connector-j</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<scope>test</scope>
		</dependency>

3. Configuring 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 (DataSourceAutoConfiguration & DataSourceProperties)
spring.datasource.url = jdbc:mysql://localhost:3306/users_database?useSSL=false
spring.datasource.username = root
spring.datasource.password = root


## Hibernate Properties
# The SQL dialect makes Hibernate generate better SQL for the chosen database
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQLDialect

# Hibernate ddl auto (create, create-drop, validate, update)
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 users_database 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 User entity that we will define in the next step. This is made possible by the property spring.jpa.hibernate.ddl-auto = update.

4. Create Employee JPA Entity

import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "employees")
public class Employee {

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private long id;
	@Column(name = "first_name", nullable = false)
	private String firstName;
	@Column(name = "last_name", nullable = false)
	private String lastName;
	@Column(name = "email_address", nullable = false)
	private String emailId;
}

5. Create Spring Data JPA Repository

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

public interface EmployeeRepository extends JpaRepository<Employee, Long>{

}

6. Exception Handling

Let's create ResourceNotFoundException class with the following content into it:
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

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

	private static final long serialVersionUID = 1L;

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

Let's create ErrorDetails class with the following content into it:

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import java.util.Date;

@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class ErrorDetails {
	private Date timestamp;
	private String message;
	private String details;
}
Let’s create a GlobalExceptionHandler class annotated with @ControllerAdvice annotation. This class handles exception-specific and global exceptions in a single place.
import java.util.Date;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

@ControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
	@ExceptionHandler(ResourceNotFoundException.class)
	public ResponseEntity<?> resourceNotFoundException(ResourceNotFoundException ex, WebRequest request) {
		ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false));
		return new ResponseEntity<>(errorDetails, HttpStatus.NOT_FOUND);
	}

	@ExceptionHandler(Exception.class)
	public ResponseEntity<?> globleExcpetionHandler(Exception ex, WebRequest request) {
		ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false));
		return new ResponseEntity<>(errorDetails, HttpStatus.INTERNAL_SERVER_ERROR);
	}
}

7. Create EmployeeController - CRUD REST API

Now, it's time to create CRUD Rest APIs for the Employee resource:

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import jakarta.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api/v1")
public class EmployeeController {
	@Autowired
	private EmployeeRepository employeeRepository;

	@GetMapping("/employees")
	public List<Employee> getAllEmployees() {
		return employeeRepository.findAll();
	}

	@GetMapping("/employees/{id}")
	public ResponseEntity<Employee> getEmployeeById(@PathVariable(value = "id") Long employeeId)
			throws ResourceNotFoundException {
		Employee employee = employeeRepository.findById(employeeId)
				.orElseThrow(() -> new ResourceNotFoundException("Employee not found for this id :: " + employeeId));
		return ResponseEntity.ok().body(employee);
	}

	@PostMapping("/employees")
	public Employee createEmployee(@Valid @RequestBody Employee employee) {
		return employeeRepository.save(employee);
	}

	@PutMapping("/employees/{id}")
	public ResponseEntity<Employee> updateEmployee(@PathVariable(value = "id") Long employeeId,
			@Valid @RequestBody Employee employeeDetails) throws ResourceNotFoundException {
		Employee employee = employeeRepository.findById(employeeId)
				.orElseThrow(() -> new ResourceNotFoundException("Employee not found for this id :: " + employeeId));

		employee.setEmailId(employeeDetails.getEmailId());
		employee.setLastName(employeeDetails.getLastName());
		employee.setFirstName(employeeDetails.getFirstName());
		final Employee updatedEmployee = employeeRepository.save(employee);
		return ResponseEntity.ok(updatedEmployee);
	}

	@DeleteMapping("/employees/{id}")
	public Map<String, Boolean> deleteEmployee(@PathVariable(value = "id") Long employeeId)
			throws ResourceNotFoundException {
		Employee employee = employeeRepository.findById(employeeId)
				.orElseThrow(() -> new ResourceNotFoundException("Employee not found for this id :: " + employeeId));

		employeeRepository.delete(employee);
		Map<String, Boolean> response = new HashMap<>();
		response.put("deleted", Boolean.TRUE);
		return response;
	}
}
Let's understand all the annotations used in the EmployeeController:

@RequestMapping("/api/v1") - annotation declares the base URL for all the APIs in this controller.

@RestController - annotation is a combination of Spring’s @Controller and @ResponseBody annotations.

@GetMapping - This annotation is used to map incoming HTTP GET requests to a specific method handler.

@PostMapping - This annotation is used to map incoming HTTP POST requests to a specific method handler.

@PutMapping - This annotation is used to map incoming HTTP PUT requests to a specific method handler.

@DeleteMapping - This annotation is used to map incoming HTTP DELETE requests to a specific method handler.

@PathVariable - This annotation is used to bind a path variable with a method parameter.

8. Running the Application

We have successfully developed all the CRUD Rest APIs for the Employee resource. now it's time to deploy our application in a servlet container(embedded tomcat). Two ways we can start the standalone Spring boot application. 

1. From the root directory of the application and type the following command to run it -
$ mvn spring-boot:run
2. From your IDE, run the Application.main() method as a standalone Java class that will start the embedded Tomcat server on port 8080 and point the browser to http://localhost:8080/.

      9. Calling REST APIs using RestTemplate Class

      RestTemplate Class Overview

      The RestTemplate provides a higher-level API over HTTP client libraries. It makes it easy to invoke REST endpoints in a single line.

      Let's list out useful RestTemplate APIs:
      • getForObject - Retrieves a representation via GET.
      • getForEntity - Retrieves a ResponseEntity (that is, status, headers, and body) by using GET.
      • headForHeaders - Retrieves all headers for a resource by using HEAD.
      • postForLocation - Creates a new resource by using POST and returns the Location header from the response.
      • postForObject - Creates a new resource by using POST and returns the representation from the response.
      • postForEntity - Creates a new resource by using POST and returns the representation from the response.
      • put - Creates or updates a resource by using PUT.
      • patchForObject - Updates a resource by using PATCH and returns the representation from the response. Note that the JDK HttpURLConnection does not support the PATCH, but Apache HttpComponents and others do.
      • delete - Deletes the resources at the specified URI by using DELETE.
      • optionsForAllow - Retrieves allowed HTTP methods for a resource by using ALLOW.
      • exchange - A more generalized (and less opinionated) version of the preceding methods that provides extra flexibility when needed. It accepts a RequestEntity (including HTTP method, URL, headers, and body as input) and returns a ResponseEntity.
      • execute - The most generalized way to perform a request, with full control over request preparation and response extraction through callback interfaces.

      Let's create a SpringRestClient class and add the following content to it:
      import java.util.Arrays;
      import java.util.HashMap;
      import java.util.Map;
      
      import org.springframework.http.HttpEntity;
      import org.springframework.http.HttpHeaders;
      import org.springframework.http.HttpMethod;
      import org.springframework.http.MediaType;
      import org.springframework.http.ResponseEntity;
      import org.springframework.web.client.RestTemplate;
      
      public class SpringRestClient {
      
      	private static final String GET_EMPLOYEES_ENDPOINT_URL = "http://localhost:8080/api/v1/employees";
      	private static final String GET_EMPLOYEE_ENDPOINT_URL = "http://localhost:8080/api/v1/employees/{id}";
      	private static final String CREATE_EMPLOYEE_ENDPOINT_URL = "http://localhost:8080/api/v1/employees";
      	private static final String UPDATE_EMPLOYEE_ENDPOINT_URL = "http://localhost:8080/api/v1/employees/{id}";
      	private static final String DELETE_EMPLOYEE_ENDPOINT_URL = "http://localhost:8080/api/v1/employees/{id}";
      	private static RestTemplate restTemplate = new RestTemplate();
      
      	public static void main(String[] args) {
      		SpringRestClient springRestClient = new SpringRestClient();
      		
      		// Step1: first create a new employee
      		springRestClient.createEmployee();
      		
      		// Step 2: get new created employee from step1
      		springRestClient.getEmployeeById();
      		
      		// Step3: get all employees
      		springRestClient.getEmployees();
      		
      		// Step4: Update employee with id = 1
      		springRestClient.updateEmployee();
      		
      		// Step5: Delete employee with id = 1
      		springRestClient.deleteEmployee();
      	}
      
      	private void getEmployees() {
      
      		HttpHeaders headers = new HttpHeaders();
      		headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
      		HttpEntity<String> entity = new HttpEntity<String>("parameters", headers);
      
      		ResponseEntity<String> result = restTemplate.exchange(GET_EMPLOYEES_ENDPOINT_URL, HttpMethod.GET, entity,
      				String.class);
      
      		System.out.println(result);
      	}
      
      	private void getEmployeeById() {
      
      		Map<String, String> params = new HashMap<String, String>();
      		params.put("id", "1");
      
      		RestTemplate restTemplate = new RestTemplate();
      		Employee result = restTemplate.getForObject(GET_EMPLOYEE_ENDPOINT_URL, Employee.class, params);
      
      		System.out.println(result);
      	}
      
      	private void createEmployee() {
      
      		Employee newEmployee = new Employee("admin", "admin", "[email protected]");
      
      		RestTemplate restTemplate = new RestTemplate();
      		Employee result = restTemplate.postForObject(CREATE_EMPLOYEE_ENDPOINT_URL, newEmployee, Employee.class);
      
      		System.out.println(result);
      	}
      
      	private void updateEmployee() {
      		Map<String, String> params = new HashMap<String, String>();
      		params.put("id", "1");
      		Employee updatedEmployee = new Employee("admin123", "admin123", "[email protected]");
      		RestTemplate restTemplate = new RestTemplate();
      		restTemplate.put(UPDATE_EMPLOYEE_ENDPOINT_URL, updatedEmployee, params);
      	}
      
      	private void deleteEmployee() {
      		Map<String, String> params = new HashMap<String, String>();
      		params.put("id", "1");
      		RestTemplate restTemplate = new RestTemplate();
      		restTemplate.delete(DELETE_EMPLOYEE_ENDPOINT_URL, params);
      	}
      }

      Before running the above REST Client code, make sure that your Spring Boot App is up and running.

      10. Running SpringRestClient class

      SpringRestClient class contains a main() method so just right-click and run as Java Application. You will see below output in the console:


      Comments