Sunday, May 22, 2022

Microservices Communication Enhancement Using Service Discovery

What is Service Discovery?

Sevice Discovery is the process of automatically detecting devices and services on a network, we will be using Eureka Server for this which detects and keep track of its registered clients.

If a microservice needs to talk to another microservice it sends a service discovery request to the eureka server and the server returns where the request will be routed.


We will be completing the project from the previous blog post.

  • Create a new maven module in your previous project and name it "eureka server"



  • Open your main pom.xml file and add the following dependency

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>

  • Open your eureka-server module pom.xml and the following dependancy

<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
  • Create an application.properties file under resources and the following configuration.
spring.application.name=eurekaServer
server.port=8461
eureka.client.fetch-registry=false
eureka.client.register-with-eureka=false
  • Create the EurekaServerApplication class
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {

public static void main(String[] args){
SpringApplication.run(EurekaServerApplication.class,args);
}
}
The @EnableEurekaServer annotation is used to make your Spring Boot application acts as a Eureka Server
  • Run the application class and open the server on the port specified just to make sure everthing is working fine as you can see there are no registered clients currenctly in eureka.



  • Now lets register the clients on the eureka server
  • Open your needed microservice in our case its the util microservices.
  • Open the util project pom.xml and add the following dependancy.
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
  • Open up the util application class and add the @EnableEurekaClient annotation
@SpringBootApplication
@EnableEurekaClient
public class UtilApplication {

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

@EnableEurekaClient annotation allows the project to be registered at the eureka server as a client.
  • Add the following property in your application.properties file
#Properties
euraka.client.service-url.defaultZone=http://localhost:8461/eureka
  • Start the util application and view the changes on the eureka server portal.
  • Notice the util application is now registered as a client on the eureka server.


  • Repeat the steps on your customer microservice
  • open your refrenced util url in the application.properties file and change the following.
notification.service.url=http://IP:Port/api/v1/email/send 
to
notification.service.url=http://UTIL/api/v1/email/send
  • Open your customer config class where the rest template used for sending the service is defined.
  • Add the annotation @LoadBalanced
The @LoadBalanced annotation will make an instance of created RestTemplate load-balanced. There is no code you need to write to make RestTemplate load-balance HTTP request it sends to an internal microservice. The RestTemplate bean will be intercepted and auto-configured by Spring Cloud

  • Run the application and test the customer microservice using a rest client.
  • The service should run normally.


You can find full project here.


Saturday, May 7, 2022

Microservices Using Spring Boot With Http Communication

What are Microservices? 

Microservices are an architectural and organizational approach to software development where software is composed of small independent services that communicate over well-defined APIs 


Project Design



Full Project on github can be found under the following link.

What you will need?

  •  Java 1.8 or later
  •  Maven
  •  Intellij IDE 
  •  Any Type of SQL DB 

Project Setup 

1) Creating the project
  • Install Maven Plugin using the following link 

To make sure the apache maven is installed correctly using the following command to confirm 
mvn --version 

  • Navigate to your directory that you need where the project is created and run the below command
mvn archetype:generate -DgroupId=com.microservices.toutrial -DartifactId=microservices.toutrial -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.4 -DinteractiveMode=false 
 
Specify your groupId and artifactId

After the project finishes building, you will receive the below message


  • Open the created project in IntelliJ IDE.

Open the main pom.xml file and add the following configuration
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.microservices.toutrial</groupId>
  <artifactId>microservices.toutrial</artifactId>
  <packaging>pom</packaging>
  <version>1.0-SNAPSHOT</version>

  <name>microservices.toutrial</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
    <spring.boot.maven.plugin.version>2.5.7</spring.boot.maven.plugin.version>
    <spring-boot-dependencies.version>2.5.7</spring-boot-dependencies.version>
  </properties>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>${spring-boot-dependencies.version}</version>
        <scope>import</scope>
        <type>pom</type>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <dependencies>
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.20</version>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
    </dependency>
  </dependencies>

  <build>
  <pluginManagement>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <version>${spring.boot.maven.plugin.version}</version>
      </plugin>
    </plugins>
  </pluginManagement>
</build>
</project>

  • Add a new module to the project 


  • Select the module type as maven.

  • Click next and specify the name and the parent module.


  • Click finish you should find the project structure below.

  • Open the customer pom file, and notice the parent reference.

  • Now notice the parent pom file having the created module referenced.



  • Creating the Customer Microservice


Add the following dependancies to the customer pom file.

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>

Now for this project i will be orginizing my code as follows


1) Create the CustomerApplication class under the main package com.microservices.customer .

@SpringBootApplication annotation is used to mark a configuration class that declares one or more @Bean methods and also triggers auto-configuration and component scanning.


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

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

}
2) Create the Entity Class
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name="customer")
public class CustomerEntity {

@javax.persistence.Id
@Column(name = "Id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long Id;

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

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

@Column(name = "email")
private String email;
}
3) Create the Repository Interface
import com.microservices.customer.core.entities.CustomerEntity;
import org.springframework.data.repository.CrudRepository;

public interface CustomerRepository extends CrudRepository<CustomerEntity,Long> {
}

4) Create the Customer Service Class.

@Service annotates classes at the service layer.

@Service
@AllArgsConstructor
public class CustomerService {

@Autowired
private CustomerRepository customerRepository;

public CustomerEntity registerCustomer(CustomerEntity customerEntity){
return customerRepository.save(customerEntity);
}
}
5) Create the datasource class

HikariDataSource

Hikari is the default DataSource implementation with Spring Boot 2

import com.zaxxer.hikari.HikariDataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class CustomerDS {

@Bean
@ConfigurationProperties("app.datasource")
public HikariDataSource hikariDataSource(){
return DataSourceBuilder
.create()
.type(HikariDataSource.class)
.build();
}
}

Add this confiugration to the application.properties file under resources (if it is not created then create a text file and name it application.properties)

app.datasource.jdbc-url=jdbc:mysql://IP:Port/microservices_customer?serverTimezone=UTC&useUnicode=yes&characterEncoding=UTF-8
app.datasource.username=
app.datasource.password=
app.datasource.pool-size=30
# Hibernate
spring.datasource.initialize=true
#spring.datasource.platform=oracle
#update-validate-create-
spring.jpa.properties.hibernate.hbm2ddl.auto=create
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect

spring.jpa.properties.hibernate.show-sql=true
spring.jpa.properties.hibernate.format_sql=true

spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.
PhysicalNamingStrategyStandardImpl


6) Moving on to the Rest Service , you will need to create a model and a controller
  • Model Class
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class CustomerModel {

private long id;
private String firstName;
private String lastName;
private String email;
}
  • Controller Class
import com.microservices.customer.core.entities.CustomerEntity;
import com.microservices.customer.core.services.CustomerService;
import com.microservices.customer.web.models.CustomerModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

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

@Autowired
CustomerService customerService;

@PostMapping(path = "/registerCustomer")
public CustomerModel registerCustomer(@RequestBody CustomerModel customerModel) {
CustomerEntity customerEntity =
customerService.registerCustomer(new CustomerEntity(null,
customerModel.getFirstName(),
customerModel.getLastName(),
customerModel.getEmail()));
return new CustomerModel(customerEntity.getId(),
customerEntity.getFirstName(),
customerEntity.getLastName(),
customerEntity.getEmail());
}
}

Now let's test what we have build , run the customer application class and use postman or any 
other client to test the microservice.




Record was created succefully in the database.

  • Creating the Email Notification Microservice.

Create a new module based on maven and name it util , this will hold all our utility microservices.



Notice that the util module is refrenced in the main pom.xml


I will be using the following strucutre to organize my code

1) Add the following dependancies in the util pom.xml file.
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
2) Create the util application class under the main package "com.microservices.util".
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class UtilApplication {

public static void main(String[] args){
SpringApplication.run(UtilApplication.class,args);
}
}
3) Create the Email Sender Intrerface to allow future dependancy Injection.
public interface EmailSender {
boolean sendEmail(String to,String subject,String email);
}
4) Create the Email Util Implementation Class.
@Service
@AllArgsConstructor
public class EmailUtil implements EmailSender {

@Autowired
private final JavaMailSender mailSender;

@Override
@Async
public boolean sendEmail(String to,String subject,String email) {
try {
MimeMessage mimeMessage = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,"utf-8");
helper.setTo(to);
helper.setText(email);
helper.setSubject(subject);
helper.setFrom("Hello@microservices.com");
mailSender.send(mimeMessage);

}catch (Exception ex){
ex.printStackTrace();
return false;
}
return true;
}
}

5) Now lets create the controller and model
  • Model Class
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class EmailModel {
private String to;
private String subject;
private String text;
}
  • Controller Class
@RestController
@RequestMapping(path = "api/v1/email")
public class EmailController {

@Autowired
private EmailUtil emailUtil;

@PostMapping(path = "/send")
public boolean sendEmail(@RequestBody EmailModel emailModel){
        return emailUtil.sendEmail(emailModel.getTo(), emailModel.getSubject(),
    emailModel.getText());
}
}

6) Finally add the configuration needed to send email in the application.properties file
i will be using gmail.
spring.application.name=Util
server.port=8083

spring.mail.host=smtp.gmail.com
spring.mail.port=587
spring.mail.username=
spring.mail.password=

# Other properties
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.connectiontimeout=5000
spring.mail.properties.mail.smtp.timeout=5000
spring.mail.properties.mail.smtp.writetimeout=5000

# TLS , port 587
spring.mail.properties.mail.smtp.starttls.enable=true
For the sake of testing you will need to enable less secure apps on gmail.


Now Lets run the Util Application Class and test the microservice using a client.

And the recieved email


Acheving Http Communication between Microservices.

  • Open the customer module and add the following referance to the email microservice to the application.properties file.
notification.service.url=http://IP:Port/api/v1/email/send
  • Create the Configuration class Customer Config
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class CustomerConfig {
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}

  • Create the Outbound Reqeust Model Bean
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;

@AllArgsConstructor
@Data
@Builder
public class NotificationServiceRequest {
private String to;
private String subject;
private String text;
} 
  • Modify the Customer Service Class to the following 
@Service
@AllArgsConstructor
public class CustomerService {

@Autowired
private CustomerRepository customerRepository;
@Autowired
Environment environment;

@Autowired
RestTemplate restTemplate;

public CustomerEntity registerCustomer(CustomerEntity customerEntity){
    customerEntity = customerRepository.save(customerEntity);
String emailBody = "New customer was registred with the user " +
customerEntity.getFirstName() + " " +customerEntity.getLastName();
NotificationServiceRequest notificationServiceRequest = new NotificationServiceRequest(
customerEntity.getEmail(),
"Registration Confirmation",
emailBody
);

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<NotificationServiceRequest> httpEntity =
new HttpEntity<>(notificationServiceRequest, headers);
restTemplate.postForObject(
environment.getProperty("notification.service.url"),
httpEntity,
String.class
);

return customerEntity;
}
}
Now lets test the changes




And the recived email upon registration.



Thats it , to be hounest this is the bare minimum , you can achieve so much more with the microservices architectural pattern.






Sunday, July 4, 2021

Spring Boot HateOAS Service Project

Spring Boot HateOAS Implementation

Hypermedia as the Engine of Application State (HATEOAS) is a constraint of the REST application architecture that distinguishes it from other network application architectures. With HATEOAS, a client interacts with a network application whose application servers provide information dynamically through hypermedia.

The full project is on GitHub and can be accessed through the following link

This project will cover the following topics
  • Initializing Spring Boot project using spring boot initializer.
  • Date base connectivity using Hikari Data source.
  • Creating Database Entities , Repositories & services using Spring JPA.
  • Exposing an API using Spring web.
  • Implementing HateOAS standard using Spring HateOAS.

Project Architecture




Initializing Spring Boot project using spring boot initializer

Create your project using the spring Spring Initializr or if its imbedded in your IDE like Intellij you can start from there


Finish Creating your project and make sure you add the following dependencies
  • spring-boot-starter-hateoas
  • spring-boot-starter-web
  • spring-boot-starter-tomcat
  • spring-boot-starter-data-jpa
  • spring-boot-starter-jdbc
  • <dependency>
    <groupId>com.oracle.database.jdbc</groupId>
    <artifactId>ojdbc8</artifactId>
    <version>21.1.0.0</version>
    </dependency>

Date base connectivity using Hikari Data source.

Hikari is a JDBC DataSource implementation that provides a connection pooling mechanism. Compared to other implementations, it promises to be lightweight and better performing.

Start by creating a new package to organize and keep everything neat and tidy , for this tourtial I used oracle database.

Create a new class lets name it "oracleDataSource" the following is its implementation.












@Configuration
public class oracleDataSource {
@Bean
@ConfigurationProperties("app.datasource")
public HikariDataSource hikariDataSource(){
return DataSourceBuilder
.create()
.type(HikariDataSource.class)
.build();
}
}


Hikari Data source uses a configuration file which is in "Yaml" structure , so go ahead 
and create that under resources "application.yaml".








define your connectivity inside as follows
app:
datasource:
jdbc-url: jdbc:oracle:thin:@localhost:1521:xe
username: ****
password: ****
pool-size: 30

notice the line of configuration class corresponds to the path in the yaml configuration file
@ConfigurationProperties("app.datasource")

now that connectivity is done we can move to creating entities and exposing some methods using jpa.


Creating Database entities using Spring JPA

We are going to create the following entities described by the below UML in our database










create a new package "core" this is where all your database activity is kept , now create another package within core and lets call it "entities" and  add the following classes implementation.

import javax.persistence.*;
import java.sql.Date;

@Entity
@Table(name="t_members")
public class membersEntity {

@javax.persistence.Id
@Column(name = "Id")
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long Id;

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

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

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

@Column(name = "telephoneNumber")
private String telephoneNumber;

@Column(name = "creationDate")
private Date creationDate;

@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "Id", referencedColumnName = "Id")
private memberDetailsEntity memberDetails;

public Long getId() {
return Id;
}

public void setId(Long id) {
Id = id;
}

public String getFirstName() {
return firstName;
}

public void setFirstName(String firstName) {
this.firstName = firstName;
}

public String getLastName() {
return lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
}

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}

public String getTelephoneNumber() {
return telephoneNumber;
}

public void setTelephoneNumber(String telephoneNumber) {
this.telephoneNumber = telephoneNumber;
}

public Date getCreationDate() {
return creationDate;
}

public void setCreationDate(Date creationDate) {
this.creationDate = creationDate;
}

public memberDetailsEntity getMemberDetails() {
return memberDetails;
}

public void setMemberDetails(memberDetailsEntity memberDetails) {
this.memberDetails = memberDetails;
}
}


import javax.persistence.*;

@Entity
@Table(name="t_member_details")
public class memberDetailsEntity {

@Id
@Column(name = "Id")
private Long Id;

private String country;
private String provinance;
private String streetName;
private String streetNumber;
private String buissnessDescription;

public Long getId() {
return Id;
}

public void setId(Long id) {
Id = id;
}

public String getCountry() {
return country;
}

public void setCountry(String country) {
this.country = country;
}

public String getProvinance() {
return provinance;
}

public void setProvinance(String provinance) {
this.provinance = provinance;
}

public String getStreetName() {
return streetName;
}

public void setStreetName(String streetName) {
this.streetName = streetName;
}

public String getStreetNumber() {
return streetNumber;
}

public void setStreetNumber(String streetNumber) {
this.streetNumber = streetNumber;
}

public String getBuissnessDescription() {
return buissnessDescription;
}

public void setBuissnessDescription(String buissnessDescription) {
this.buissnessDescription = buissnessDescription;
}



@OneToOne
@JoinColumn(name = "Id")
private membersEntity member;
}


Now you need to create  the repositories as extensions of crud repository , create a new package under core "repository".


import com.toutrial.resthateos.core.entities.membersEntity;
import org.springframework.data.repository.CrudRepository;
import java.util.Set;

public interface membersRepository extends CrudRepository<membersEntity,Long> {

Set<membersEntity> findAllByFirstNameOrLastName(String firstName,String lastName);

membersEntity findById(long Id);

}

import com.toutrial.resthateos.core.entities.memberDetailsEntity;
import org.springframework.data.repository.CrudRepository;

public interface memberDetailsRepository extends CrudRepository<memberDetailsEntity,Long>{
}


now for the services  , create a new service class package under core "services".
the service acts as a business layer to access the queries.

@Service
public class membersBl {

@Autowired
private membersRepository members;

@Autowired
private memberDetailsRepository memberDetails;

public membersEntity createMember(membersEntity member){
try{
member.setCreationDate(new Date(new java.util.Date().getTime()));
return members.save(member);
}catch (Exception ex) {
return null;
}
}

public Set<membersEntity> getAllByName(String name){
return members.findAllByFirstNameOrLastName(name,name);
}

public membersEntity getById(long Id){
return members.findById(Id);
}

public Optional<memberDetailsEntity> getDetailsById(long Id){
return memberDetails.findById(Id);
}

}


Exposing an API using Spring web.

What you need to build a rest service is a controller and model , lets start by building the model used by the service.

the model here is basically what the API consumes and produces

create a package lets call it web , create another package under that and name it models.

Member Model

notice that the model created extends RepresentationModel<> which is a container for a collection 
of Links and provides APIs to add those links to the existing model.

public class memberModel extends RepresentationModel<memberModel> {

private Long Id;
private String firstName;
private String lastName;
private String telephoneNumber;
private String email;
private Date creationDate;

public Long getId() {
return Id;
}

public void setId(Long id) {
Id = id;
}

public String getFirstName() {
return firstName;
}

public void setFirstName(String firstName) {
this.firstName = firstName;
}

public String getLastName() {
return lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
}

public String getTelephoneNumber() {
return telephoneNumber;
}

public void setTelephoneNumber(String telephoneNumber) {
this.telephoneNumber = telephoneNumber;
}

public Date getCreationDate() {
return creationDate;
}

public void setCreationDate(Date creationDate) {
this.creationDate = creationDate;
}

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}
}

Member Details Model

public class memberDetailsModel extends RepresentationModel<memberDetailsModel> {
private Long Id;
private String country;
private String provinance;
private String streetName;
private String streetNumber;
private String buissnessDescription;

public Long getId() {
return Id;
}

public void setId(Long id) {
Id = id;
}

public String getCountry() {
return country;
}

public void setCountry(String country) {
this.country = country;
}

public String getProvinance() {
return provinance;
}

public void setProvinance(String provinance) {
this.provinance = provinance;
}

public String getStreetName() {
return streetName;
}

public void setStreetName(String streetName) {
this.streetName = streetName;
}

public String getStreetNumber() {
return streetNumber;
}

public void setStreetNumber(String streetNumber) {
this.streetNumber = streetNumber;
}

public String getBuissnessDescription() {
return buissnessDescription;
}

public void setBuissnessDescription(String buissnessDescription) {
this.buissnessDescription = buissnessDescription;
}
}
in a normal rest api you can associate the member model to the member details model but since we
are implementing hateos we are using links to retrieve the data at need

now lets create the controller , create a member controller class under the package controllers

@RestController
@RequestMapping("/api/v1/member/")
public class memberController {

@Autowired
membersBl membersService;

@GetMapping(path = "getByName/{name}")
public CollectionModel<memberModel> getMemberByName(@PathVariable("name") String name){
List<memberModel> members = new ArrayList<>();

membersService.getAllByName(name).stream().forEach(membersEntity -> {
memberModel member = new memberModel();
member.setId(membersEntity.getId());
member.setCreationDate(membersEntity.getCreationDate());
member.setFirstName(membersEntity.getFirstName());
member.setLastName(membersEntity.getLastName());
member.setEmail(membersEntity.getEmail());
member.setTelephoneNumber(membersEntity.getTelephoneNumber());

//Link selfLink = linkTo(methodOn(memberController.class)).slash(name).withSelfRel();
//member.add(selfLink);

Link memberLink = linkTo(methodOn(memberController.class)
.getById(member.getId())).withRel("getById");
member.add(memberLink);

Link memberDetailsLink = linkTo(methodOn(memberController.class)
.getDetailsById(member.getId())).withRel("getDetailsById");
member.add(memberDetailsLink);

members.add(member);
});

Link link = linkTo(memberController.class).slash("getByName").slash(name).withSelfRel();
CollectionModel<memberModel> result = CollectionModel.of(members, link);
return result;
}

@GetMapping(path = "getById/{Id}")
public memberModel getById(@PathVariable("Id") long Id){
membersEntity membersEntity = membersService.getById(Id);
memberModel member = new memberModel();
member.setId(membersEntity.getId());
member.setFirstName(membersEntity.getFirstName());
member.setLastName(membersEntity.getLastName());
member.setEmail(membersEntity.getEmail());
member.setTelephoneNumber(membersEntity.getTelephoneNumber());
member.setCreationDate(membersEntity.getCreationDate());

Link link = linkTo(memberController.class).slash("getById").slash(Id).withSelfRel();
member.add(link);

return member;
}


@PostMapping(path = "createMember")
public actionModel createMember(@RequestBody memberModel member){

membersEntity memberRecord = new membersEntity();
memberRecord.setFirstName( member.getFirstName());
memberRecord.setLastName(member.getLastName());
memberRecord.setEmail(member.getEmail());
memberRecord.setTelephoneNumber(member.getTelephoneNumber());
memberRecord = membersService.createMember(memberRecord);

actionModel result = new actionModel();
if(memberRecord.getId() > 0){
result.setAction(true);
result.setMessage("success");

Link memberLink = linkTo(methodOn(memberController.class)
.getById(memberRecord.getId())).withRel("getById");
result.add(memberLink);
}else{
result.setAction(false);
result.setMessage("failed");
}
return result;
}

@PostMapping(path = "getDetailsById/{Id}")
public memberDetailsModel getDetailsById(long Id){
Optional<memberDetailsEntity> mDetails = membersService.getDetailsById(Id);

memberDetailsModel model = new memberDetailsModel();
mDetails.ifPresent(memberDetailsEntity -> {
model.setId(memberDetailsEntity.getId());
model.setCountry(memberDetailsEntity.getCountry());
model.setProvinance(memberDetailsEntity.getProvinance());
model.setStreetName(memberDetailsEntity.getStreetName());
model.setStreetNumber(memberDetailsEntity.getStreetNumber());
model.setBuissnessDescription(memberDetailsEntity.getBuissnessDescription());

Link link = linkTo(memberController.class).slash("getDetailsById").slash(Id).withSelfRel();
model.add(link);
});

return model;

}

}

This Code Snippet utilizes the extended model to reference the service links used to retrieve detail data 
now you can populate your data base and run the application , using a client invoke the method 
Link memberLink = linkTo(methodOn(memberController.class)
.getById(member.getId())).withRel("getById");
member.add(memberLink);

Link memberDetailsLink = linkTo(methodOn(memberController.class)
.getDetailsById(member.getId())).withRel("getDetailsById");
member.add(memberDetailsLink);

Link link = linkTo(memberController.class).slash("getByName").slash(name).withSelfRel();
CollectionModel<memberModel> result = CollectionModel.of(members, link);


"getByName" => /api/v1/member/getByName/yacoub




notice the model is returned in a _embeded tag and the links added successfully to the service response


Microservices Communication Enhancement Using Service Discovery

What is Service Discovery? Sevice Discovery is the process of automatically detecting devices and services on a network, we will be using Eu...