Complete microservices architecture with real examples — Step 2 — User microservice

Hi everyone! As in the previous post, we are going to implement a complete microservice architecture and as the first step, we have created a microservice which is called Department Service and for the sake of complexity which can handle with the architecture, we need one more service which has a call to the Department Service within it. So, here in this post, we will try to implement another service called User Service. we will quickly go into the implementation details.

This image is recreated by agnasarp.com and used only for information purposes. This does not have any bind with any real-world products or services. Image source: pixabay.com

Step 2 — User Microservice

Here we will quickly go to the technology stack that we are going to use in our implementation.

Initialization details

Spring Initialzr — User Service
  • Project build tool: Maven
  • Language: Java
  • Spring boot: 2.4.2
  • Project Metadata

Group: com.agnasarp

Artifact: agnasarp-user-microservice

Name: agnasarp-user-microservice

Description: Agnasarp User Microservice

Package name: com.agnasarp.user

Packaging: Jar

Java version: 8

  • Dependencies:

Spring Web: Build web, including RESTful, applications using Spring MVC. Uses Apache Tomcat as the default embedded container.

Spring Data JPA: Persist data in SQL stores with Java Persistence API using Spring Data and Hibernate.

H2 Database: Provides a fast in-memory database that supports JDBC API and R2DBC access, with a small (2mb) footprint. Supports embedded and server modes as well as a browser based console application.

Lomok: Java annotation library which helps to reduce boilerplate code.

Project Structure

Project structure of user service in IntelliJ Idea

pom.xml

<?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.4.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.agnasarp</groupId>
<artifactId>agnasarp-user-microservice</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>agnasarp-user-microservice</name>
<description>Agnasarp User Microservice</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>2020.0.1</spring-cloud.version>
</properties>
<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>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>

</project>

application.yml

server:
port: 8380

AgnasarpUserMicroserviceApplication.java

package com.agnasarp.user;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
public class AgnasarpUserMicroserviceApplication {

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

@Bean
RestTemplate restTemplate() {
return new RestTemplate();
}
}

UserController.java

package com.agnasarp.user.controller;

import com.agnasarp.user.entity.User;
import com.agnasarp.user.service.UserService;
import com.agnasarp.user.vo.ResponseTemplateVo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/users")
public class UserController {
private static final Logger log = LoggerFactory.getLogger(UserController.class);
@Autowired
private UserService userService;

@PostMapping("/")
public User saveUser(@RequestBody User user) {
log.info("Inside saveUser method of UserController");
return userService.saveUser(user);
}

@GetMapping("/{id}")
public ResponseTemplateVo getUserById(@PathVariable("id") Long userId) {
log.info("Inside getUserById method of UserController");
return userService.getUserWithDepartment(userId);
}
}

UserService.java

package com.agnasarp.user.service;

import com.agnasarp.user.entity.User;
import com.agnasarp.user.repository.UserRepository;
import com.agnasarp.user.vo.Department;
import com.agnasarp.user.vo.ResponseTemplateVo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

@Service
public class UserService {
private static final Logger log = LoggerFactory.getLogger(UserService.class);
@Autowired
private UserRepository userRepository;
@Autowired
private RestTemplate restTemplate;

public User saveUser(User user) {
log.info("Inside saveUser method of UserService");
return userRepository.save(user);
}

public ResponseTemplateVo getUserWithDepartment(Long userId) {
log.info("Inside getUserWithDepartment method of UserService");
ResponseTemplateVo responseTemplateVo = new ResponseTemplateVo();
User user = userRepository.getUserByUserId(userId);
Department department = restTemplate.getForObject("http://localhost:8280/departments/" + userId, Department.class);
responseTemplateVo.setUser(user);
responseTemplateVo.setDepartment(department);
return responseTemplateVo;
}

}

UserRepository.java

package com.agnasarp.user.repository;

import com.agnasarp.user.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
User getUserByUserId(Long userId);
}

User.java

package com.agnasarp.user.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

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

@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long userId;
private String firstName;
private String lastName;
private Long departmentId;
}

View Objects

We need the attached department details of the user, therefore we have to create a Department view object here in the user microservice. And we need to show user details and department details collectively in the response, for that we have to create ResponseTemplateVo.

Department.java

package com.agnasarp.user.vo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Department {
private Long departmentId;
private String departmentName;
private String departmentAddress;
private String departmentCode;
}

ResponseTemplateVo.java

package com.agnasarp.user.vo;

import com.agnasarp.user.entity.User;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class ResponseTemplateVo {
private User user;
private Department department;

public void setUser(User user) {
this.user = user;
}

public void setDepartment(Department department) {
this.department = department;
}
}

Service call

Create user scenario

cURL

curl --location --request POST 'http://localhost:8380/users/' \
--header 'Content-Type: application/json' \
--data-raw '{
"firstName":"John",
"lastName":"Smith",
"departmentId":"1"
}'

Postman call

Save user scenario

Get user scenario: As we have designed to get user details with the assigned department, we have to create a department first with the save department service as in the previous post. Otherwise, the department object will be null.

cURL

curl --location --request GET 'http://localhost:8380/users/1'

Postman call

Get user scenario

Now we have created the User Microservice successfully as same as the Department Service in the previous post. As the next step, we will create a service registry which is another important component in the microservice architecture. You can download the complete source code from GitHub with the below link.

Download source from github: https://github.com/Agnasarp/agnasarp-user-microservice

Go to Step 1 — Department Microservice

Originally published at https://www.agnasarp.com on February 19, 2021.

Agnasarp is a technology-focused blog that has enough information about cutting-edge technologies that you can use for your problems. Stay with us!