Welcome back to My First Tech Series (#MyFirstTechSeries). Today we will see how to create a simple micro service. Our service will perform CRUD operations on customer data such as customer name, mobile number and email address. And, we will use Postgres SQL as our backend.
STEP 1: INSTALLATION OF SPRING PLUG-IN
To begin, we need to have Spring Tool Suite installed in our IDE. For that, navigate to Help --> Eclipse Marketplace. Search for "Spring Tools" and hit Go. Choose to install Spring Tools 4.
Hit Confirm, Accept Terms and Conditions and hit Finish.
Please wait till the software is installed. Look out for the progress bar in the bottom right corner of eclipse IDE.
After installation, eclipse will ask for restart. Click Restart Now.
STEP 2: CREATE THE FIRST PROJECT
Navigate to File --> New --> Other --> Spring Starter Project
Give a name for your micro service. I have chosen demo-rest-service. Also give the group and package name. I have given com.ninja.demo. A general best practice is to give com.companyname.projectname. Also modify the description if necessary
Hit Next..
Add necessary dependencies. You can add them directly from here or you can later add in to the pom.xml file. For this project, I am choosing the following:
Spring Web -
Spring Data JDBC - for having a JDBC Connection for data access.
Postgres SQL Server - this is the DB we will be using. You can choose based on your DB.
Spring Data JPA - to avoid unnecessary boilerplate code. This helps in significantly reducing our coding efforts.
Lombok - generates code using easy annotations. to avoid boilerplate code. Example: It automatically creates getter setter methods for entity object.
Click Next > and Finish.
Project is created successfully in eclipse with all our chosen dependencies available in pom.xml. This is our created project structure.
We are done with the project creation. We will move on with the next step.
STEP 3: SETTING UP THE POSTGRES SERVER
Download the Postgres SQL from here based on your OS and install in your system : https://www.postgresql.org/download/ At the time of writing, the version is 13.3. If you use this installation method, ignore the next bullet about brew.
As applicable, give the following details:
Username: postgres
Password : admin
Port : 5432 (This is default port for postgress, advisable not to change this)
Alternatively, You can also use brew to install in your system. I used brew. Note: It does take a few minutes to install using brew. If you use brew, then the installation command is
brew install postgresql
brew install --cask pgadmin4
Now open pgAdmin 4 in your system. Provide a master password for pgAdmin. I have given the password as "admin". I know it's not safe, but it is easy to remember.
STEP 4: STARTING THE SPRING BOOT SERVER
Set up Application Port:
Often times, we get exception that "Port is already in use". To avoid this, it is always a best practice to have a dedicated port for the server. Port Number can be anything. I chose 1234. To set this port number, goto src/main/resources --> application.properties . In that file, type
server.port=1234
Then, we have to give Postgres SQL properties. (Username, password, url etc). Also, we have to In the same file, also type create tables in Postgres and keep modifying the table based on our entity object definition.
spring.datasource.url=jdbc:postgresql://localhost:5432/postgres
spring.datasource.username=postgres
spring.datasource.password=admin
spring.jpa.hibernate.ddl-auto=update
The final application.properties file is as follows:
#Server Properties
server.port=1234
#PostGres Properties
spring.datasource.url=jdbc:postgresql://localhost:5432/postgres
spring.datasource.username=postgres
spring.datasource.password=admin
#To create tables in PostGres if not already created
spring.jpa.hibernate.ddl-auto=update
Save the application.properties file.
Now let us test if the server is running. Navigate to src/main/java --> package com.ninja.demo --> DemoRestServiceApplication.java.
Right click --> Run As --> Spring Boot App
Console output's last line should be: "Started DemoRestServiceApplication".
If you have reached this far, then you have successfully finished your project setups. Give yourself a pat on your back, as you have crossed more than half the sea.
STEP 5: CODING THE APPLICATION- PACKAGE AND CLASS CREATION
The best codes often lie in organized packages. So, let us create packages first and then create classes within. Under com.ninja.demo package, Right click --> New --> Package. The packages to be created are:
com.ninja.demo.controller <-- This is for the controller
com.ninja.demo.entity <-- This is for entity / object / model layer
com.ninja.demo.jpa <-- This is for the service repository and database access layer
After creating packages, create java classes under the respective packages. The filenames to be created are:
DemoController.java under com.ninja.demo.controller
DemoEntity.java under com.ninja.demo.entity
DemoRepository.java under com.ninja.demo.jpa
STEP 6: CODING THE APPLICATION- DEPENDENCY CONFIGURATION
We must add a few dependencies manually to our pom.xml. Remember to Clean and Build the project after any modification to the pom.xml
Spring boot starter validation --> Necessary for Entity Validations
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
2. javax.persistence --> Necessary for Entity, ID auto generation etc.
<!-- https://mvnrepository.com/artifact/javax.persistence/javax.persistence-api -->
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>javax.persistence-api</artifactId>
<version>2.2</version>
</dependency>
3. Jpa --> Necessary for JPA repository
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-jpa -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>2.5.3</version>
</dependency>
4. Springfox - Swagger and Swagger UI
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.7.0</version>
</dependency>
After adding all dependencies, our final pom.xml code will be as follows:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.3</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.ninja</groupId>
<artifactId>demo-rest-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo-rest-service</name>
<description>Demo project for Spring Boot - First Microservice</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- <dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency> -->
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.persistence/javax.persistence-api -->
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>javax.persistence-api</artifactId>
<version>2.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-jpa -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>2.5.3</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.7.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
STEP 7: CODING THE APPLICATION- CREATE THE MODEL/ENTITY/OBJECT
First let us create the model / entity. We create 3 fields - Customer Name, Email and City along with autogenerated Customer ID. All annotations necessary for the Entity (Getter, Setter, Constructors etc.) are also included.
package com.ninja.demo.entity;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
@Entity
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString
@EqualsAndHashCode
public class DemoEntity {
@Id
@GeneratedValue (strategy = GenerationType.AUTO)
Long customerID;
@NotBlank (message = "Customer Name is mandatory")
String customerName;
String customerEmail;
String customerCity;
}
STEP 8: CODING THE APPLICATION- CREATE THE REPOSITORY/SERVICE
Next up is the DemoRepository.java. If the logic is complicated, we may require an additional file DemoService.java. But since we are having a simple logic, just DemoRepository.java is sufficient. JpaRepository has inbuilt functions. The code is as follows:
package com.ninja.demo.jpa;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.ninja.demo.entity.DemoEntity;
@Repository
public interface DemoRepository extends JpaRepository<DemoEntity, Long> {
}
STEP 9: CODING THE APPLICATION- CREATE THE CONTROLLER AND DEFINE REST ENDPOINTS/METHODS
We have to define the service endpoints for different methods(Get, Post, Put, Delete) in the controller DemoController.java. The code is as follows:
package com.ninja.demo.controller;
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
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;
import com.ninja.demo.jpa.DemoRepository;
import com.ninja.demo.entity.DemoEntity;
@RestController
@RequestMapping("/")
public class DemoController {
// DemoEntity is the Customer Object
@Autowired
DemoRepository demoRepository;
// Get All Customers
@GetMapping("/customers")
List<DemoEntity> all(){
return demoRepository.findAll();
}
// Get Single Customer
@GetMapping("/customers/{id}")
Optional <DemoEntity> findCustomer(@PathVariable Long id){
return demoRepository.findById(id);
}
// Create New Customer
@PostMapping("/customers")
DemoEntity createCustomer (@RequestBody DemoEntity newCustomer) {
return demoRepository.save(newCustomer);
}
// Update Customer Information
@PutMapping("/customers/{id}")
DemoEntity updateCustomer (@RequestBody DemoEntity updatedCustomer, @PathVariable Long id) {
return demoRepository.save(updatedCustomer);
}
// Delete Single Customer
@DeleteMapping ("/customers/{id}")
void deleteCustomer(@PathVariable Long id){
demoRepository.deleteById(id);
}
}
STEP 10: CODING THE APPLICATION- TIE IT ALL TOGETHER
Finally, the spring application's main class should know the packages containing the entity, service and controller. Hence, we should add a ComponentScan annotation in the DemoRestServiceApplication.java. Also, we must include swagger specification here. The source code is as follows.
package com.ninja.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@SpringBootApplication
//@ComponentScan({ "com.ninja.demo.controller, com.ninja.demo.entity, com.ninja.demo.jpa" })
@ComponentScan(basePackages="com.ninja.demo")
@EnableSwagger2
public class DemoRestServiceApplication {
public static void main(String[] args) {
SpringApplication.run(DemoRestServiceApplication.class, args);
}
@Bean
public Docket demoApi() {
return new Docket(DocumentationType.SWAGGER_2).select().apis(RequestHandlerSelectors.basePackage("com.ninja.demo")).build();
}
}
STEP FINAL: TEST THE SERVICES
Start the server.
Test the different methods using a rest client such as postman. We have already included coding for Swagger and hence we can use swagger to test our services.
The Swagger UI URL is : http://localhost:1234/swagger-ui.html
Create / POST JSON body is:
{
"customerName": "Jane Doe",
"customerEmail": "janeDoe@ninja.com",
"customerCity": "Seattle"
}