The REST API architecture is the de facto standard used by most applications to work with data on the internet.

This is usually the case when implementing features using third-party solutions. After implementing your API, you can use front-end frameworks such as Angular and React to create, view, and edit data.

In this tutorial, you will learn how to create a REST API using Spring Boot and PostgreSQL. However, this tutorial will not cover the front end. You will test the API using Postman.

Prerequisites

Project setup

To create a new project, go to spring intialzr, and select Maven in the Project section, select Java in the Language section, and select 3.0 in the Spring Boot section.

On the Project Metadata section, enter the respective sections as shown below.

  • Group – com.javawhizz
  • Artifact – RESTAPI
  • Package name – com.javawhizz.RESTAPI
  • Packaging – Jar
  • Java – 17

Press the ADD DEPENDENCIES button and add the dependencies: Spring Web, Lombok, PostgreSQL Driver, and Spring Data JPA.

The project structure and dependencies of your project should be as shown below.

project structure and dependencies

  • Spring Web – Library to provide you with features to implement REST APIs.
  • Lombok – reduce boilerplate code by generating getter methods, setter methods, and others.
  • PostgreSQL Driver – to connect your application with the PostgreSQL database.
  • Spring Data JPA – object-relational mapping tool for Java.

Press the GENERATE button to generate a ZIP file containing the project. Unzip the project and import it into IntelliJ.

Add database connection properties

Rename the application.properties file to application.yml and copy and paste the following properties into the file. Change the username and password to match your database credentials.

spring:
  datasource:
    url: jdbc:postgresql://localhost:5432/rest_api_db
    username: postgres
    password: javawhizz
  jpa:
    hibernate:
      ddl-auto: create-drop
    properties:
      hibernate:
        dialect: org.hibernate.dialect.PostgreSQLDialect
        format_sql: true
    show-sql: true

This file sets the database to be used by the application as rest_api_db. The create-drop property configures the application to create tables every time the application starts and to drop the tables every time the application stops.

Since there are different database management systems, the dialect property sets the database to PostgreSQLDialect. The format_sql property pretty prints the SQL generated by Hibernate to the console. The show_sql property configures the application to log the generated SQL.

Create Customer model

Create a file named Customer.java under the package src/main/java/com/javawhizz/RESTAPI/customer and copy and paste the following code into the file.

package com.javawhizz.RESTAPI.customer;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import lombok.Data;

@Data
@Entity
public class Customer {

    @Id
    @GeneratedValue
    private Integer customerId;

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

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

    @Column(name = "email")
    private String email;
}

To generate getters and setters, add the @Data annotation. This annotation is used in place of @Getter and @Setter annotations.

The @Entity annotation is used by Hibernate to create a database table named customer. The fields for the table are annotated using @Column annotation.

Create Customer repository

Create a file named CustomerRepository.java under the package src/main/java/com.javawhizz/RESTAPI/customer and copy and paste the following code into the file.

package com.javawhizz.RESTAPI.customer;

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

public interface CustomerRepository extends JpaRepository<Customer, Integer> {

}

To execute queries using Spring Data JPA, you are required to implement the JpaRepository interface. In design patterns, this programming approach is called the Template method pattern.

Since the interface is generic, In the first argument pass the domain type to be managed by the repository which in this case is the customer model. In the second argument pass the type of ID being used by the model which in this case is an Integer.

Create a Customer service interface

Create a file named CustomerService.java under the package src/main/java/com.javawhizz/RESTAPI/customer and copy and paste the following code into the file.

package com.javawhizz.RESTAPI.customer;

import java.util.Optional;

public interface CustomerService {
    Integer createCustomer(Customer customer);
    Optional<Customer> findCustomer(Integer customerId);

    Customer updateCustomer(Integer customerId, 
                            Customer customer);

    void deleteCustomer(Integer customerId);
}

This interface defines four methods for all the CRUD methods that you will implement in the next section. Additionally, you can inject this interface into any class and call the methods without implementing them and this helps you reduce the boilerplate code.

Implement the Customer service interface

Create a file named CustomerServiceImpl.java under the package src/main/java/javawhizz/RESTAPI/customer and copy and paste the following code into the file.

package com.javawhizz.RESTAPI.customer;

import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.Optional;

@Service
@RequiredArgsConstructor
public class CustomerServiceImpl implements CustomerService{

    private final CustomerRepository customerRepository;
    @Override
    public Integer createCustomer(Customer customer) {
        return customerRepository
                .save(customer).getCustomerId();
    }

    @Override
    public Optional<Customer> findCustomer(Integer customerId) {
        return customerRepository
                .findById(customerId);

    }

    @Override
    public Customer updateCustomer(Integer customerId, Customer customer) {
        Customer theCustomer = customerRepository.findById(customerId)
                .stream()
                .findFirst()
                .orElseThrow(
                        () -> new RuntimeException(
                        String.format("customer with id %s does not exist",
                                customer.getCustomerId())));

        theCustomer.setFirstName(customer.getFirstName());
        theCustomer.setLastName(customer.getLastName());
        theCustomer.setEmail(customer.getEmail());

        return customerRepository
                .save(theCustomer);
    }

    @Override
    public void deleteCustomer(Integer customerId) {
        Customer theCustomer = customerRepository
                .findById(customerId).get();
        if (theCustomer == null){
            throw new RuntimeException(
                    String.format("The customer with id %s does not exist",
                            customerId));
        }
        customerRepository
                .delete(theCustomer);

    }
}

To implement the code to perform CRUD operations on the database, implement the CustomerService and all the methods defined in it.

The createCustomer() method calls the save() method of repository and passes the new customer instance to persist to the database. If the customer is persisted successfully the method returns the ID of the customer.

Since you can fetch a customer that does not exist in the database, the findCustomer() method first checks if the user is present and returns if one is found.

The updateCustomer() method is the only method that accepts two parameters. The first parameter is for the ID of the customer to be updated and the second parameter contains the changes to be made.

The save() method is used to create and update a customer. Since the deleteCustomer() method removes a customer from the database, it does not return any value. Always write business logic to check if an item exists in the database before deleting it.

Create Customer Controller

Create a file named CustomerController.java under the package src/main/java/com/javawhizz/RESTAPI/customer and copy and paste the following code into the file.

package com.javawhizz.RESTAPI.customer;

import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("api/v1/customer")
@RequiredArgsConstructor
public class CustomerController {

    private final CustomerService customerService;
    @PostMapping
    public ResponseEntity<Integer>
    createCustomer(@RequestBody Customer customer){
        Integer customerId =
                customerService.createCustomer(customer);
        return new ResponseEntity<>
                (customerId, HttpStatus.CREATED);
    }

    @GetMapping("{id}")
    public ResponseEntity<Customer>
    findCustomer(@PathVariable("id") Integer customerId){
        Customer theCustomer =
                customerService.findCustomer(customerId)
                .stream().findFirst()
                .orElseThrow(() ->
                        new RuntimeException(
        String.format("customer with id %s does not exist", customerId)));
        return new ResponseEntity<>
                (theCustomer, HttpStatus.OK);
    }

    @PutMapping("{id}")
    public ResponseEntity<Customer>
    updateCustomer(@PathVariable("id") Integer customerId,
                   @RequestBody Customer customer){
        Customer theCustomer =
                customerService
                        .updateCustomer(customerId, customer);
        return new ResponseEntity<>
                (theCustomer, HttpStatus.OK);
    }

    @DeleteMapping("{id}")
    public ResponseEntity<HttpStatus>
    deleteCustomer(@PathVariable("id") Integer customerId){
        customerService.deleteCustomer(customerId);
        return new ResponseEntity<>(HttpStatus.OK);
    }
}

A controller provides the base path that you can use to execute the CRUD operations on the database. The base path maps to a different HTTP request for each operation.

For example, the @PostMapping is used to make a request to create data, the @GetMapping is used to make a request to fetch data, the @PutMapping is used to make a request to update data and the @DeleteMapping is used to make a request to delete data.

Each HTTP request will be based on the CRUD operation being executed. To realize this, inject the CustomerService using the @RequiredArgsConstructor and call the respective methods for each of them.

To add HTTP status code to your response, return a ResponseEntity with the data being returned. This applies to the first three methods. The last method only returns HttpStatus because it does return a value.

Run and test the application

To run the application, press the run icon located on the top right side of IntelliJ. If your application has no errors, you should see the SQL for creating the customer table on the console.

running the application

To test the application, open Postman and test each of the requests as shown in the following images.

Create Customer

test create customer api

Find Customer

test find customer api

Update Customer

test update customer api

Delete Customer

test delete customer api

Conclusion

In this tutorial, you have learned how to create REST APIs using Spring Boot and PostgreSQL. This tutorial has covered CRUD operations and you can add other queries that can be implemented in an application.

For example, you can create a feature to fetch a customer by email or fetch all the customers in the database. Since this tutorial used Postman to test the APIs, you will later learn how to use add the front end to interact with your APIs.

The front end will be implemented using Thymeleaf and Bootstrap. You will not cover how to use Angular or React since the frameworks are outside the scope of this tutorial. Stay tuned for the front-end tutorial.

The code for this tutorial is available on GitHub. You can also watch a Youtube video of this tutorial if you prefer learning visually.

Happy Coding!


0 Comments

Leave a Reply

Avatar placeholder

Your email address will not be published. Required fields are marked *