Microservices Communication via HTTP and JSON

A microservice architecture is used to build an application as a collection of loosely coupled, independently deployable services. These applications can interact with each other to achieve synergistic functionality. The most common way for microservices to communicate is to use JSON as the data exchange format using HTTP which is a widely supported protocol. It can provide a reliable way for any service to send a request and receive a response. JSON is a small data exchange format and is easy to parse and manipulate.

Microservices communicate via HTTP by calling each other’s APIs. Each microservice can expose a RESTful API and other microservices can interact with these APIs to perform various tasks. JSON can be used as a data exchange format because it is lightweight and easy to work with.

Overview of how microservices communicate

  • Service discovery: Microservices can register with a user discovery tool like Eureka so they can find each other.
  • API Gateway: This can act as an entry point for clients, sending requests to the appropriate microservices.
  • HTTP requests: Microservices can send HTTP requests to communicate with each other via JSON to exchange data.

Implementation of the Microservices Communication via HTTP and JSON

We will develop the two simple microservices. Then two services will communicate through the HTTP and JSON of the application.

Create the User-Service

Step 1: Create a new Spring Boot project using Spring Initializr, and add the below dependencies:

  • Spring Web
  • Apache ActiveMQ
  • Spring DevTools
  • Lombok

After this project creation done, the project structure will be like below:


Step 2: Open application.properties file and add the application name, server port configuration of the project.

spring.application.name=user-service
server.port=8082


Step 3: Create the User class

Go to src > org.example.userservice > model > User and put the below code.

Java
package org.example.userservice.model;


import lombok.Data;

@Data
public class User {
    private String userId;
    private String name;
    private String email;

    public User() {
    }

    public User(String userId, String name, String email) {
        this.userId = userId;
        this.name = name;
        this.email = email;
    }
  
}


Step 4: Create the UserService class.

Go to src > org.example.userservice > service > UserService and put the below code.

Java
package org.example.userservice.service;


import org.example.userservice.model.User;
import org.springframework.stereotype.Service;



@Service
public class UserService {
    public User getUserById(String userId) {
        return new User(userId, "John Doe", "john@example.com");
    }

    public User getUserByName(String name) {
        // Mock data, in real scenarios, fetch from database
        if ("John Doe".equals(name)) {
            return new User("U12345", name, "john@example.com");
        }
        return null;
    }
}


Step 5: Create the UserController Class

Go to src > org.example.userservice > controller > UserController and put the below code.

Java
package org.example.userservice.controller;


import org.example.userservice.model.User;
import org.example.userservice.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;


@RestController
@RequestMapping("/users")
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping("/{userId}")
    public ResponseEntity<User> getUser(@PathVariable String userId) {
        User user = userService.getUserById(userId);
        return ResponseEntity.ok(user);
    }

    @GetMapping("/byname")
    public ResponseEntity<User> getUserByName(@RequestParam String name) {
        User user = userService.getUserByName(name);
        return ResponseEntity.ok(user);
    }
}


Step 6: Open the main class. (No changes are required)

Java
package org.example.userservice;

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

@SpringBootApplication
public class UserServiceApplication {

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

}


pom.xml:

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>3.2.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>org.example</groupId>
    <artifactId>user-service</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>user-service</name>
    <description>user-service</description>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <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>
            <optional>true</optional>
        </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>

    <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>


Step 7: Run the application

Now we will run the project and it will run at port 8082.


Create the Order-service

Step 1: Create a new Spring Boot project using Spring Initializr, and add below dependencies:

  • Spring Web
  • Apache ActiveMQ
  • Spring DevTools
  • Lombok

After the Project creation done, the folder structure will be like below image.


Step 2: Open application.properties file and add the application name, server port configuration.

spring.application.name=order-service

server.port=8081


Step 3: Create the Order class

Go to src > org.example.orderservice > model > Order and put the below code.

Java
package org.example.orderservice.model;

import lombok.Data;

@Data
public class Order {
    private String orderId;
    private String userId;
    private double amount;

    public Order() {
    }

    public Order(String orderId, String userId, double amount) {
        this.orderId = orderId;
        this.userId = userId;
        this.amount = amount;
    }
}


Step 4: Create the OrderDetails class

Go to src > org.example.orderservice > model > OrderDetails and put the below code.

Java
package org.example.orderservice.model;


import lombok.Data;

@Data
public class OrderDetails {
    private Order order;
    private User user;

    public OrderDetails() {
    }

    public OrderDetails(Order order, User user) {
        this.order = order;
        this.user = user;
    }
 
}


Step 5: Create the User class

Go to src > org.example.orderservice > model > User and put the below code.

Java
package org.example.orderservice.model;

import lombok.Data;

@Data
public class User {
    private String userId;
    private String name;
    private String email;

    public User() {
    }

    public User(String userId, String name, String email) {
        this.userId = userId;
        this.name = name;
        this.email = email;
    }
 
}


Step 6: Create the RestTemplateConfig class

Go to src > org.example.orderservice > config > RestTemplateConfig and put the below code.

Java
package org.example.orderservice.config;


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class RestTemplateConfig {

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


Step 7: Create the OrderService class

Go to src > org.example.orderservice > service > OrderService and put the below code.

Java
package org.example.orderservice.service;


import org.example.orderservice.model.Order;
import org.example.orderservice.model.OrderDetails;
import org.example.orderservice.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;


import org.springframework.web.client.ResourceAccessException;



@Service
public class OrderService {

    @Autowired
    private RestTemplate restTemplate;

    public OrderDetails getOrderDetails(String orderId) {
        // Mock data
        Order order = new Order(orderId, "U12345", 250.75);
        User user = restTemplate.getForObject("http://localhost:8082/users/" + order.getUserId(), User.class);
        return new OrderDetails(order, user);
    }

    public OrderDetails getOrderDetailsByUserName(String name) {
        try {
            User user = restTemplate.getForObject("http://localhost:8082/users/byname?name=" + name, User.class);
            if (user != null) {
                // Mock data
                Order order = new Order("12345", user.getUserId(), 250.75);
                return new OrderDetails(order, user);
            } else {
                return null;
            }
        } catch (ResourceAccessException e) {
            System.err.println("Error connecting to UserService: " + e.getMessage());
            return null;
        }
    }
}


Step 8: Create the OrderController class

Go to src > org.example.orderservice > controller > OrderController and put the below code.

Java
package org.example.orderservice.controller;


import org.example.orderservice.model.OrderDetails;
import org.example.orderservice.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;


@RestController
@RequestMapping("/orders")
public class OrderController {

    @Autowired
    private OrderService orderService;

    @GetMapping("/{orderId}")
    public ResponseEntity<OrderDetails> getOrder(@PathVariable String orderId) {
        OrderDetails orderDetails = orderService.getOrderDetails(orderId);
        return ResponseEntity.ok(orderDetails);
    }

    @GetMapping("/byusername")
    public ResponseEntity<OrderDetails> getOrderByUserName(@RequestParam String name) {
        OrderDetails orderDetails = orderService.getOrderDetailsByUserName(name);
        return ResponseEntity.ok(orderDetails);
    }
}


Step 9: Open the main class and write the below code. (No changes are required)

Java
package org.example.orderservice;

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 OrderServiceApplication {

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


pom.xml:

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>3.2.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>org.example</groupId>
    <artifactId>order-service</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>order-service</name>
    <description>order-service</description>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <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>
            <optional>true</optional>
        </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>

    <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>


Step 10: Run the application

Once we run the application, the application will start at port 8081.


Order by username Endpoint Testing:

GET http://localhost:8081/order/byusername?name=John Doe

Output:

By following these steps, we can set up the two microservices (UserService, OrderService ) that communicate via the HTTP using JSON. This example project demonstrates how microservices can interact seamlessly and it allow us to build scalable and maintainable applications.