How to Create a Spring Boot REST API

How to Create a Spring Boot REST API

Maddy's photo
ยทNov 21, 2021ยท

8 min read

Table of contents

In my previous article, I wrote about Spring Boot Architecture. I think Spring Boot is great to create REST APIs.

If you're wondering what a REST API is, "REST" stands for * Representational State Transfer*. It's a way to communicate between applications over the HTTP.

This article will show you how to create a REST API with Spring Boot from scratch.

For project development, I've used:

  • IntelliJ IDEA 2020+

  • Maven 3+

  • MySQL Workbench 8+

  • Postman v9+

1. Generate the Project

Go to the website Spring Initializr to initialize the Spring Boot project. Add the following dependencies:

  • Spring Boot DevTools: to give us the development tools.

  • Lombok: to help us reduce boilerplate code (for example, getters and setters).

  • Spring Web: to embed Apache Tomcat and include Spring MVC.

  • Spring Data JPA: to facilitate the database layer.

  • MySQL Driver: to enable the communication between the Spring Boot application and the database.


Click "Generate" and then import the project onto your IDE as a Maven project.

This is going to be my package structure:


This is my pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="" xmlns:xsi=""
        <relativePath/> <!-- lookup parent from repository -->
    <description>Demo project for Spring Boot</description>



2. Database Configuration

Once you have created the table, let's ensure that the database is set up properly with the application to allow communication between the two.

The script below should go inside the under src/main/resources.

spring.datasource.url = jdbc:mysql://localhost:3306/customer-management-system
spring.datasource.username = root
spring.datasource.password = Connection
spring.jpa.hibernate.ddl-auto = update = org.hibernate.dialect.MySQL5Dialect

server.error.include-stacktrace = never

server.port = 8083

3. Create a Mysql Database Table

I created a database schema called "customer-management-system".

Then, you can run the query below to create a Customer table.

    first_name VARCHAR(100),
    last_name VARCHAR(100),
    email VARCHAR(100),
    phone_number VARCHAR(255),
    PRIMARY KEY (customer)

Nice! We're done with all the housekeeping. Now let's jump onto the more interesting part.

4. Create a Model Class

The model class is a class that represents a real-world object. It's responsible for *storing* and retrieving the data.

Instead, the entity class is a Java class mapped to a database table, and each field corresponds to a database column. I found an interesting discussion on Quora if you'd like to know more about the difference between a model and an entity.

In the example below, we created a Customer model and linked each Java field to the columns in the database.


  • The @ Data is a Lombok annotation that puts together getters, setters, toString method, equals, hashcode, etc.

  • The @ Column must match the name of the columns in the database.

package com.techwithmaddy.CustomerAPI.model;

import lombok.Data;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Table(name = "Customer")
public class Customer {

    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id")
    private Integer id;

    @Column(name = "first_name")
    private String firstName;

    @Column(name = "last_name")
    private String lastName;

    private String email;

    @Column(name = "phone_number")
    private String phoneNumber;


5. Create a Customer Repository Interface

The repository is an interface responsible for performing database query operations. It extends the JPA Repository, which has CRUD operations built in.

The type arguments are "Customer", the domain class that will be managed, and "Integer", which is the type of id of the domain class.

In this interface, we created a method to find a customer via email.

NOTE: @ Query is a Spring Data JPA annotation used to create customized database queries.

package com.techwithmaddy.CustomerAPI.repository;

import com.techwithmaddy.CustomerAPI.model.Customer;

public interface CustomerRepository extends CrudRepository<Customer, Integer> {

    @Query("SELECT c FROM Customer c WHERE =:email")
    Customer findCustomerByEmail(String email);


6. Create a Service Class

The service class is responsible for defining the business logic of our application.

The service class communicates with the repository (and the controller, which we'll build later).

For Dependency Injection, Spring can use auto-wiring. With the Autowired annotation, Spring will search for a class that matches the property by type, and it will automatically inject the object.

In the service class, we have two methods:

  1. saveCustomer(): this is going to save the customer into the database. The good thing about extending the CRUD repository is that it provides built-in CRUD functions(such as save() ), so we don't need to define them into the service class explicitly.

  2. getCustomerByEmail(): this is going to retrieve the customer using their email. I used the Optional to handle a possible NullPointerException (what if the email we type doesn't exist?).

package com.techwithmaddy.CustomerAPI.service;

import com.techwithmaddy.CustomerAPI.model.Customer;
import com.techwithmaddy.CustomerAPI.repository.CustomerRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Optional;

public class CustomerService {

    private CustomerRepository customerRepository;

    public Customer saveCustomer(Customer savedCustomer) {
        Customer customer = new Customer();

    public Optional<Customer> getCustomerByEmail(String email){
        Customer customer = customerRepository.findCustomerByEmail(email);

        return Optional.ofNullable(customer);


7. Create a Custom Exception

Along with the service class, we also create a CustomerNotFoundException class that we're going to use to throw an Exception in case a customer doesn't exist.

package com.techwithmaddy.CustomerAPI.exception;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

public class CustomerNotFoundException extends RuntimeException {
    public CustomerNotFoundException(){
        super("Customer Not Found");

8. Create a Controller Class

The controller class is responsible for handling the requests coming from the client.

This controller is where we explicitly say that this application is a REST API, thanks to the @ RestController annotation. This class will handle the requests.

Then, we use the RequestMapping, which is the parent annotation of all the other mappings.

In this class, we have two methods:

  • saveCustomer(): this method saves the information of the customer into the database. We make use of the POST request to create new data.

We write the POST request like this:

  • getCustomerByEmail(): this method retrieves data from the database using the email. If the email doesn't exist, then we throw a CustomerNotFoundException.

We write the GET request like this:

package com.techwithmaddy.CustomerAPI.api;

import com.techwithmaddy.CustomerAPI.exception.CustomerNotFoundException;
import com.techwithmaddy.CustomerAPI.model.Customer;
import com.techwithmaddy.CustomerAPI.service.CustomerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;

import static org.springframework.web.bind.annotation.RequestMethod.GET;
import static org.springframework.web.bind.annotation.RequestMethod.POST;

@RequestMapping(value = "/customer")
public class CustomerController {

    private CustomerService customerService;

    @RequestMapping(method = {POST}, path = "/save", produces = MediaType.APPLICATION_JSON_VALUE)
    public Customer saveCustomer(@Valid @RequestBody Customer customer){
        return customerService.saveCustomer(customer);

    @RequestMapping(method = {GET}, path = "/retrieve")
    public Customer getCustomerByEmail(@RequestParam String email){
        return customerService.getCustomerByEmail(email).orElseThrow(CustomerNotFoundException::new);


9. Create a Validation Handler Class

This class allows us to customize the response we're going to receive on Postman.

You can read more about this class here.

package com.techwithmaddy.CustomerAPI.validation;

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

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

public class ValidationHandler extends ResponseEntityExceptionHandler {

    protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex,
                                                                  HttpHeaders headers, HttpStatus status, WebRequest request) {

        Map<String, String> errors = new HashMap<>();
        ex.getBindingResult().getAllErrors().forEach((error) -> {

            String fieldName = ((FieldError) error).getField();
            String message = error.getDefaultMessage();
            errors.put(fieldName, message);
        return new ResponseEntity<Object>(errors, HttpStatus.BAD_REQUEST);

10. Postman

Now we can test the application using Postman.

Let's add a couple of customers.

Enter the body of the request:

    "firstName": "Steve",
    "lastName": "Austin",
    "email": "",
    "phoneNumber": "01223344556"

Hit SEND, and Steve Austin will be saved into the database.


Let's try again with another customer.

    "firstName": "Linda",
    "lastName": "Delgado",
    "email": "",
    "phoneNumber": "01345678999"

Linda Delgado is also saved into our database.


On Postman, you should get a 200 OK status response.


Let's see the scenario when:

  • the phone number is less or greater than 10.

  • the email address is invalid.


As you can see, we get a customized error message.

Now that we know how to save a customer and have a couple of customers saved in our database, we can make a GET request to retrieve a customer via email.

Let's retrieve the customer, Steve.


And now Linda.


If we try to retrieve a customer that doesn't exist, we get a 404 status code, as we should expect.


Some tips when you create your own application:

  • Follow the recommended Spring Boot package structure.

  • Running mvn clean install helps clean the dependencies and build the project, in case you remove or rename a resource from the directory.

  • Ensure that you click on the right imports.

  • Ensure that Postman accepts application/json to avoid 415 Unsupported Media Type.

  • Ensure that you set the database schema as default schema .


In this tutorial, you have learned how to create a Spring Boot REST API.

We have:

  • Generated a Spring Boot project.

  • Created a database.

  • Linked the application to the database.

  • Created a RestController, Service and a Repository.

  • Created a Custom Exception.

  • Used Postman to test the REST API.

If you ever want to play with the application, you can clone the Github repository here.

Thanks for reading my article, until next time! ๐Ÿ‘‹๐Ÿพ


Did you find this article valuable?

Support Maddy by becoming a sponsor. Any amount is appreciated!

See recent sponsors |ย Learn more about Hashnode Sponsors
Share this