Build RESTful Services with Spring Boot 2.X in Few Steps
Spring Boot is built on top of Spring framework. With zero or minimum customization, it significantly reduces the efforts to develop Spring-based and production-grade applications by doing the heavy lifting of auto-configuration and dependency management under the hood. As a result, developers are able to genuinely focus on business-centric features.
This story is going to demonstrate how we build the RESTful services with Spring Boot in few steps. We will create a simple customer service to CRUD(a.k.a. create, read, update, delete) the customer records and banking accounts each customer has.
Table of Contents
Spring Initializr
Spring Initializr is the first stop along the unfolded journey of Spring Boot. Its used to create Spring Boot application with consistent project structure. Before Spring Boot, we need to figure out the project structure and decide where to keep the configuration files, property files, and the static files so forth. Having worked in different projects in the past, I’ve seen similar java projects with varying project structure. Let's open the web-based interface to start. Fill in the fields as the following screenshot shows and click ‘Generate Project’ button.
- Group: com.codespeaks.rest
- Artifact: customerservice
- Name: customerservice
- Package Name: com.codespeaks.rest.customerservice
- Dependencies: Web, JPA, H2
The POM file as follows denotes dependencies of the starter project. In Spring Boot, different starter project is representing different Spring module such as MVC, ORM etc. What developers mostly do is to add the starter project in the dependencies, Spring Boot will manage the transitive dependencies and versions.
if we run mvnw dependency:tree
command, the underlying dependency hierarchy will show as follows
Application Properties
We use the YAML (Yet Another Markup Language) based property file to define the configuration properties as its more readable than application.properties.
- spring:application:name=customer-service # application name
- spring:h2:console:enabled=true # enable embedded h2 console. We are using the in-memory database.
spring:h2:console:path=/h2-console # Path at which the h2 console is available, we will use h2 console to check in memory data later on. - spring:jpa:show-sql=true # enable logging of SQL statements.
- server:port=8080 # Server HTTP port.
- server:servlet:context-path=/restapi # the base URL of the RESTful services
Domain Entities
In this example, we define JPA entities to showcase the following ER diagram where Customer
entity holds one to many relationship with Account
entity. Account.CustomerId
is the foreign key referring to Customer.CustomerId
.
The classes are denoted as the JPA entities with the following annotations
- @Entity denotes the class is an entity.
- @Table denotes the database table to which this entity is mapping.
- @Id denotes the primary key of the entity
- @GeneratedValue denotes the strategy of generating the primary key, the default strategy is the AUTO strategy.
- @Column denotes the column mapping of entity attribute.
- @ManyToOne denotes many to one relationship from
Account
toCustomer
. This relationship is specified on the child entityAccount
in this example. We are not defining a bi-directional relationship by using@OneToMany
annotation on relationship parentCustomer
side as the pagination will be a problem should we retrieve the accounts fromCustomer
entity. - @JoinColumn denotes the foreign key column
- @OnDelete denotes the cascade delete action in this example. When
Customer
entity gets deleted, all its accounts will be removed at the same time. - @JsonIgnore denotes the property to be ignored by JSON parser during serialization end deserialization.
Repositories
Spring Data JPA abstracts the persistence layer on top of the relational database and significantly decreases the amount of boilerplate code on CRUD operations and pagination. By extending the JPARepository
interface which has to be typed with JPA entity and its primary key type, Spring Data will detect the interface and create implementation automatically at runtime. The CRUD methods that become readily available from inheritance cover most of data access use cases out of the box.
With JPARepository
, we can also create custom queries by defining the interface methods. Spring Data JPA derives the query from the method name and implement the query logic at runtime. The followingfindByCustomerCustomerId
method accepts the argument pageable
that is of type Pageable
and returns Page
object typed with Account
class. This is all regarding the pagination and will be demonstrated in the demo.
RESTful Controllers
The controller annotated with @Controller
annotation in Spring MVC (Model-View-Controller) incorporates the business logic and controls the data flow between the model and view. The controller methods in most cases return ModelAndView
object in order to render the view. But sometimes the value returned from controller methods is displayed to users in the format of JSON/XML instead of HTML page. To make this happen, annotation @ResponseBody
comes into play and automatically serialize the returned value into JSON/XML which later is saved into the HTTP response body. The annotation @RestController
combines the proceeding annotations and offers more convenience to create RESTful controllers.
The annotations @GetMapping
, @PostMapping
, @PutMapping
, and @DeleteMapping
are more HTTP request specific than its predecessor @RequestMapping
which needs to denote the HTTP request method bymethod
variable separately.
ResponseEntity
is used in some of the RESTful controller methods to represent the whole response which includes status code, headers, and response body. Unlike the @ReponseBody
annotation which only populates the response body in the HTTP response, it gives us more freedom to manipulate the whole HTTP response.
Here are the two controller classes for Customer and Account related operations respectively.
In preceding controller classes, we defined a bunch of RESTful URIs as follows to operate with the resource Customer
and Account
.
- /customers HTTP Get # Get all customers
- /customers HTTP Post # Create a new customer
- /customers/{customerId} HTTP Get # Get a customer
- /customers/{customerId} HTTP Delete # Delete a customer
- /customers/{customerId} HTTP Put # Update an existing customer
- /customers/{customerId}/accounts HTTP Post #Create an account for a customer
- /customers/{customerId}/accounts HTTP Get #Get accounts from a customer
- /customers/{customerId}/accounts/{accountId} HTTP Delete # Delete an account from a customer
- /customers/{customerId}/accounts/{accountId} HTTP Put # Update an account from a customer
In regards to the RESTful API design guidelines, it goes beyond the scope of this article. There are some good articles out there on the internet, check here and here.
Demo
The RESTful service examples can be found on Github. If you are not comfortable with Linux curl command, we can use Postman to call the RESTful services by simply importing the Postman collection file.
To check the data in the database, we can access H2 console via http://localhost:8088/restapi/h2-console/ with the details given below.
Driver Class: org.h2.Driver
JDBC URL: jdbc:h2:mem:testdb
User Name: sa
Password: <blank>
Conclusion
Spring Boot is not competing with the Spring framework. Quite on the contrary, it makes Spring easier to use. With starter projects, Spring Boot manages the dependencies and frees us from time consuming and error-prone dependency management especially when the application complexity increases. Also, Spring Boot does the auto-configuration for us by checking the classpath. If the JPA implementation, for example, is present in the classpath, the DataSource
, TransactionManager
, and EntityManagerFactory
etc will be configured by Spring Boot. At the same time, overriding the configuration Spring Boot does for us is straightforward and easy to implement.
All code can be found on GitHub