Create a REST API with Spring Boot

Mathan Jeya
Voice Tech Podcast
Published in
11 min readApr 21, 2019

Why Spring Boot?

Spring Boot is a framework that bootstraps a Java web application without the XML configuration headaches that come with a typical Spring application. The framework adopts an opinionated approach to configuration by making decisions based on the use cases that fit the majority of modern web apps. In other words, it follows the philosophy of convention over configuration.

With Spring Boot, we can create an application that bundles all dependencies and it’s servlet container so it doesn’t even require a traditional WAR deployment. We’ll have a fat executable JAR that can be run as a standard Linux service.

Dive In to New App

Let’s imagine we’re developing a restaurant reservation application called AnnexResto to compete with OpenTable. Users can create an account, search for restaurants, book a reservation, and receive notifications via SMS or e-mail.

The application consists of the following micro services:

Account

Search

Restaurant

Reservation

Search

Messaging

Each of these micro services has a REST API and its own MySQL database. The services will be accessed by desktop and mobile users via an API gateway.

In this article, we’ll focus on building the API for the Restaurant micro service.

REST Endpoints

Our application will expose the following endpoints:

GET /v1/reservations — Retrieves all reservations

GET /v1/reservations/{id} -Retrieves a specific reservation based on ID

POST /v1/reservations — Creates a new reservation

PUT /v1/reservations/{id} — Updates an existing reservation

DELETE /v1/reservations/{id} — Removes a specific reservation based on ID

Technology Stack

We’ll be using the following technologies for the application:

Spring Tool Suite (STS) 3.83 Better I’ll prefer IntelliJ for Better Work Experience

Spring Boot 1.5.1

Spring Data JPA 1.11

Spring MVC 4.3.6

MySQL 5.7

Maven 3.3.9

Getting Started

There are a few different ways that we can begin development:

Use the Spring Boot CLI

Use the Spring Initalizer tool

Use an IDE like Spring Tool Suite (STS)

We’ll use the Spring Tool Suite for this project. IntelliJ is customized for developing Spring applications with spring boot Plugin in Market Place. It comes with built-in Tomcat server, validation of config files among other handy features that makes life easier.

Installing Spring Tool Suite

Spring Tool Suite comes packaged as a zip file and does not use an install wizard or store anything in the Windows registry. So we can just unzip the file and put it anywhere.

On first launch, it will ask us where we want our workspace to live. This is the directory that holds all of our projects and settings.

Creating the Project

Let’s launch Spring Tool Suite and select File->New -> Spring Starter projector or launch IntelliJ and select File->New -> Maven project

We can configure it as a Maven project and enter the Group, Artifact, and Package as below. Click Next.

The next screen will ask to select our dependencies. These selections will get populated into Maven’s pom.xml file.

For our project, we want the following dependencies:

Core -> Dev Tools

This dependency makes development easier for us by adding some neat features like automatic Tomcat restarts after each file change. Not required but useful to have.

SQL -> JPA, MySQL

These dependencies will allow our app to communicate with a MySQL/MariaDB database. JPA is the Java Persistence framework and will do the heavy lifting on the querying side so we don’t have to write boilerplate SQL statements for routine operations.

Web -> Web

This dependency allows us to create a REST API based on Spring MVC

Click Finish to create the project.

Maven pom.xml

Our project has now been created so let’s look at the Maven configuration file. Double-click on the file in Package Explorer and go to the tab named “pom.xml” in the main window pane.

Parent project

We’ve got a parent project named spring-boot-start-parent

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.1.RELEASE</version>
</parent>

This configuration block declares that our project is a child of the parent project and thus inherits a host of default Maven configurations.

Dependencies

Now let’s check out the dependencies section:

<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>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

These artifacts (and their own dependencies) have all been downloaded automatically by Maven and the JARs can be viewed by expanding the Maven dependencies under Package Explorer:

Build

In order to make our final JAR executable, we’ll need to add an element named executable into this section:

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<executable>true</executable>
</configuration>
</plugin>
</plugins>
</build>

Application Class

The Application class containing the main method is created for us automatically by the Project wizard.

package com.codebyamir.springboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ReservationApp {public static void main(String[] args) {
SpringApplication.run(ReservationApp.class, args);
}}

Notice that the class is annotated with @SpringBootApplication. This annotation is shorthand for three annotations: @Configuration, @EnableAutoConfiguration and @ComponentScan.

What does this do for us?

  • @Configuration tags the class as a source of bean definitions for the application context.
  • @EnableAutoConfiguration tells Spring Boot to start adding beans based on class path settings, other beans, and various property settings.
  • @ComponentScan tells Spring to look for other components, configurations, and services in the the com.codebyamir.springboot package.

Notice that there was no XML configuration required.

Our main method delegates to Spring Boot’s SpringApplication class by calling run. SpringApplication will bootstrap our application, starting Spring which will in turn start the embedded Tomcat server.

We need to pass SeatingNow.class as an argument so SpringApplication knows the primary component.

The static run method performs a number of important setup tasks:

Sets the default configuration

Starts Spring application context

Performs classpath scan

Starts Tomcat server

If we run the project as a Java application (Right click project -> Run As -> Spring Boot Application), we see a bunch of output in the console with some fancy ASCII art:

We’ve started Tomcat server on localhost with its default port 8080. Let’s check it out in our browser:

http://localhost:8080

We get an error page from the Tomcat server.

What’s happening here? There is no mapping for “/” so it tries to go to “/error” but there’s no mapping for that either so it returns a 404.

This is normal so no worries. The server is running, but we haven’t defined any API endpoints yet.

Set server.error.whitelabel.enabled=false in application.properties to switch the whitelabel error page off and restore the default error page from Tomcat.

Build better voice apps. Get more articles & interviews from voice technology experts at voicetechpodcast.com

Populate the Database

One of the tenets of micro service architecture is one database per service. So let’s create and initialize the database with some sample data:

CREATE DATABASE Annex_reservation;USE Annex_reservation;CREATE TABLE reservation (
`id` int(1) NOT NULL AUTO_INCREMENT,
`user_id` int(1) NOT NULL,
`party_size` tinyint(1) NOT NULL,
`date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`restaurant_id` int(1) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB CHARSET=utf8;
INSERT INTO reservation VALUES
(NULL,100,2,NOW(),800),
(NULL,101,3,NOW() + INTERVAL 1 DAY,800),
(NULL,102,5,NOW() + INTERVAL 2 DAY,800)

Here we are creating 3 reservations that correspond to users 100, 101, and 102.

  • Mathan(user_id=100) has a reservation for 2 at restaurant XYZ (restaurant_id=800) on 3–11–2017 at 6pm
  • Tyron(user_id=101) has a reservation for 3 at restaurant XYZ (restaurant_id=800) on 3–12–2017 at 6pm
  • Theepan(user_id=102) has a reservation for 5 at restaurant XYZ (restaurant_id=800) on 3–13–2017 at 6pm

The columns user_id and restaurant_id would typically be foreign key references to other table columns named user.id and restaurant.id but we are simplifying things here a bit.

Entity Class

In order to model a reservation, we need to create a class called Reservation which is annotated with @Entity marking it as a JPA entity.

We’ll store the reservation id, name of the person who made the reservation, the reservation date/time, and the size of the party.

Since our class name is in title case (Reservation) and our table name is in lower case (reservation), we’ll need to let Spring know about this by using @Table(name=”reservation”) before our class declaration.

We tell Spring the private key of our table by using the @Id annotation. The @Column annotations are for other columns we want to use. If any of the database column names differ from our instance variables, then we must explicitly specify the database column name as part of the annotation — @Column(name=”user_id”)

Hint : Avoid camel case column names in your database because Hibernate converts these into snake case.

package com.mathan.springboot.reservation;
import java.time.LocalDateTime;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

// Model class

@Entity
@Table(name="reservation")
public class Reservation {

@Id
private Long id;

@Column
private LocalDateTime dt;


@Column(name="user_id")
private Long userId;

@Column(name="restaurant_id")
private Long restaurantId;

public Long getRestaurantId() {
return restaurantId;
}

public void setRestaurantId(Long restaurantId) {
this.restaurantId = restaurantId;
}

// Hibernate will convert camel case column names to snake case!!!
// Don't use camelcase columns in DB
@Column(name="party_size")
private int partySize;
public Reservation() {}

public Reservation(Long id, Long userId, int partySize) {
this.id = id;

this.userId = userId;
this.partySize = partySize;
}

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public LocalDateTime getDt() {
return dt;
}

public void setDt(LocalDateTime dt) {
this.dt = dt;
}

public Long getUserId() {
return userId;
}

public void setUserId(Long userId) {
this.userId = userId;
}

public int getPartySize() {
return partySize;
}

public void setPartySize(int partySize) {
this.partySize = partySize;
}

}

Repository Interface

In a typical Java application, we would expect to write a class that implements ReservationRepository. But since we’re using Spring Data JPA, we don’t have to worry about that. JPA will create an implementation on the fly during run-time.

All we have to do is extend the CrudRepository interface like below:

package com.mathan.springboot.reservation;
import org.springframework.data.repository.CrudRepository;
public interface ReservationRepository extends CrudRepository<Reservation,String> {

}

We specify the generic parameters for the entity and ID that we are working with (Reservation and String). We will inherit several methods for saving, deleting, and finding Reservation entities.

We may also define our own methods here if we wish like findByDate() and findByLastName(). For this example, we do not need to define any additional methods.

Service Class

We now create our service class named ReservationService and annotate it with @Service.

Service classes contain the business logic and call methods in the repository layer.

package com.mathan.springboot.reservation;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class ReservationService {

@Autowired
private ReservationRepository reservationRepository;

// Retrieve all rows from table and populate list with objects
public List getAllReservations() {
List reservations = new ArrayList<>();
reservationRepository.findAll().forEach(reservations::add);
return reservations;
}

// Retrieves one row from table based on given id
public Reservation getReservation(Long id) {
return reservationRepository.findOne(id);
}

// Inserts row into table
public void addReservation(Reservation reservation) {
reservationRepository.save(reservation);
}

// Updates row in table
public void updateReservation(Long id, Reservation reservation) {
reservationRepository.save(reservation);
}

// Removes row from table
public void deleteReservation(Long id) {
reservationRepository.delete(id);
}
}

Controller Class

In order to handle HTTP requests, we must add a controller. This will be a Java class named ReservationController with a @RestController annotation applied to it.

Inside this class, we define methods that handle the actions for each URI by using the @RequestMapping annotation. The controller class creates an instance of class ReservationService to perform its work thanks to the @Autowired annotation.

package com.mathan.springboot.reservation;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/v1")
public class ReservationController {

@Autowired
private ReservationService reservationService;

// ------------ Retrieve all reservations ------------
@RequestMapping(value = "/reservations", method = RequestMethod.GET)
public List getAllReservations() {
return reservationService.getAllReservations();
}

// ------------ Retrieve a reservation ------------
@RequestMapping(value = "/reservations/{id}", method = RequestMethod.GET)
public Reservation getReservation(@PathVariable String id) {
return reservationService.getReservation(id);
}
// ------------ Create a reservation ------------
@RequestMapping(value = "/reservations", method =RequestMethod.POST)
public void addReservation(@RequestBody Reservation reservation) {
reservationService.addReservation(reservation);
}

// ------------ Update a reservation ------------
@RequestMapping(value = "/reservations/{id}", method = RequestMethod.PUT)
public void updateReservation(@RequestBody Reservation reservation,@PathVariable String id) {
reservationService.updateReservation(id, reservation);
}

// ------------ Delete a reservation ------------
@RequestMapping(value = "/reservations/{id}", method = RequestMethod.DELETE)
public void deleteReservation(@PathVariable String id) {
reservationService.deleteReservation(id);
}
}

JPA Converter Class

JPA does not know how to serialize LocalDateTime objects which poses a problem for us since our entity class has one. The solution to this problem is to create a helper class that instructs JPA on conversion:

package com.mathan.springboot.reservation;

import java.sql.Timestamp;
import java.time.LocalDateTime;

import javax.persistence.AttributeConverter;
import javax.persistence.Converter;

@Converter(autoApply = true)
public class LocalDateTimeAttributeConverter implements AttributeConverter {

@Override
public Timestamp convertToDatabaseColumn(LocalDateTime locDateTime) {
return (locDateTime == null ? null : Timestamp.valueOf(locDateTime));
}

@Override
public LocalDateTime convertToEntityAttribute(Timestamp sqlTimestamp) {
return (sqlTimestamp == null ? null : sqlTimestamp.toLocalDateTime());
}
}

Configuration with application.properties

In this project, we will use an application.properties file in /src/main/resources. Spring Boot reads this file on startup to determine how to connect to our database.

server.address=127.0.0.1
spring.datasource.url=jdbc:mysql://localhost:3306/AnnexDB?autoReconnect=true&useSSL=false
spring.datasource.username=root
spring.datasource.password=mathan95
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

Start the Application

Let’s restart the application and see how it looks. The console output will tell us if there are any issues connecting to the database.

Test the API

We have a few options for testing the API. Some popular utilities are curl (command-line) and Postman (GUI). We can also use the browser for any GET requests.

Retrieve all reservations [GET /v1/reservations]

curl -X GET -H "Content-Type: application/json" http://localhost:8080/v1/reservations

[
{
"id": 1,
"dt": {
"dayOfMonth": 12,
"dayOfWeek": "SUNDAY",
"dayOfYear": 71,
"month": "MARCH",
"monthValue": 3,
"year": 2017,
"hour": 21,
"minute": 1,
"nano": 0,
"second": 11,
"chronology": {
"id": "ISO",
"calendarType": "iso8601"
}
},
"userId": 100,
"restaurantId": 800,
"partySize": 2
},
{
"id": 2,
"dt": {
"dayOfMonth": 13,
"dayOfWeek": "MONDAY",
"dayOfYear": 72,
"month": "MARCH",
"monthValue": 3,
"year": 2017,
"hour": 21,
"minute": 1,
"nano": 0,
"second": 11,
"chronology": {
"id": "ISO",
"calendarType": "iso8601"
}
},
"userId": 101,
"restaurantId": 800,
"partySize": 3
},
{
"id": 3,
"dt": {
"dayOfMonth": 14,
"dayOfWeek": "TUESDAY",
"dayOfYear": 73,
"month": "MARCH",
"monthValue": 3,
"year": 2017,
"hour": 21,
"minute": 1,
"nano": 0,
"second": 11,
"chronology": {
"id": "ISO",
"calendarType": "iso8601"
}
},
"userId": 102,
"restaurantId": 800,
"partySize": 5
}
]

Delete a reservation [DELETE /v1/reservations/2]

curl -X DELETE -H "Content-Type: application/json" -H "Cache-Control: no-cache""http://localhost:8080/v1/reservations/2"

Run the Executable JAR as a Linux Service

The executable jar is named reservation-microservice-0.0.1-SNAPSHOT.jar.

We can run it as a Linux System V init service like so:

# ln -s /home/ec2-user/reservation-microservice-0.0.1-SNAPSHOT.jar /etc/init.d/springApp# /etc/init.d/springApp
Usage: /etc/init.d/springApp {start|stop|force-stop|restart|force-reload|status|run}

The script supports the standard service start, stop, restart and status commands.

Writes a PID file in /var/run/springApp/springApp.pidWrites console logs to /var/log/springApp.log

Backend Done Wait for the next Blog on Connecting Spring Boot With React for building a Crud Application with MYSQL.

Follow Up for more articles …

Cheers Se you all \^/

--

--

Mathan Jeya
Voice Tech Podcast

Software Engineer in Web and Mobile Applications. Likes to write about tech, coding, investing, finance & economics. Believes in adding value to people’s lives.