Consuming API in microservices using http

Using synchronous communication via HTTP for communication between two microservices

This context will be developed using a microservices called “ms-order” and another called “ms-delivery”. The first will expose the API’s and the second microservices will make the requests via HTTP to obtain the details of an order in the “ms-order”.

Creating “ms-order” microservices

In this microservice we will use a business example of the marketplace Order. Make sure that you set up docker mongoDB and RabbitMQ. Below run the DevPrime CLI. In this context create in RabbitMQ the queues “orderevents and deliveryevents”.

dp new ms-order --state mongodb --stream rabbitmq --marketplace order --init

At the end the first microservice will be ready for production and with the API’s built by the DevPrime CLI accelerator. Run the microservices “ms-order”
.\run.ps1 ou ./run.sh (Linux, macOS)

Open the microservice “ms-order” browser in the url “https://localhost:5001 or http://localhost:5000” and post to the API to create an order.

Creating “ms-delivery” microservices

Now we will create ms-delivery and add an aggregate root named “Delivery”.
dp new ms-delivery --state mongodb --stream rabbitmq

Enter the ms-delivery folder and add an Aggregate Root
dp add aggregate Delivery

After executing the commands open the file “Delivery.cs” in the folder ms-delivery/src/Core/Domain/Aggregates/Delivery and add the code below in the aggregate root “Delivery” to complement the functionality required by our implementation.
code src/Core/Domain/Aggregates/Delivery/Delivery.cs

namespace Domain.Aggregates.Delivery;
    public class Delivery : AggRoot
    {
       public DateTime Started { get; private set;}
       public DateTime Finished { get; private set;}
       public Guid OrderID { get; private set;}
       public double Total { get; private set;}      
    }

After adding the code, run the DevPrime CLI to build the basic implementations of the “ms-delivery” microservice
dp init

At the end you will already have the microservice “ms-delivery” ready to use. To meet our scenario we will do some customizations. At first it is important to remember to change the ports in the Web Adapter in the ms-delivery/src/App/appsettings.json configuration file to 5002 and 5003 to avoid conflict with the “ms-order” when on tour.
code src/App/appsettings.json

"DevPrime_Web": {
    "url": "https://localhost:5003;http://localhost:5002",
    "enable": "true",
    "enableswagger": "true",
    "PostSuccess": "201",
    "PostFailure": "500",
    "GetSuccess": "200",
    "GetFailure": "500",
    "PatchSuccess": "200",
    "PatchFailure": "500",
    "PutSuccess": "200",
    "PutFailure": "500",
    "DeleteSuccess": "200",
    "DeleteFailure": "500"
},

After change you can run the project and confirm the portal change through the DevPrime log. It is important to reinforce the presence of the automatic log provided by the Observability adapter. Finish the project and follow the next steps.

Creating a DomainEvent and a DTO

We will now create a ‘DeliveryGetOrder’ dominío event and a Handler to implement the external access call using http. Or DevPrime CLI provides an accelerator to add home events.

We will need a Data Transfer Object (DTO) to convert the result of the “ms-order” API. The first step is to create the src/Core/Application/EventHandlers/Delivery/Model folder if it does not exist and add a new “OrderCreated.cs” file with the text below.

Open the file by vscode
code src/Core/Application/EventHandlers/Delivery/Model/OrderCreated.cs

Add the code

namespace Application.EventHandlers.Delivery.Model;
    public class OrderCreated: ServicesResult
    {
        public double Total { get; set; }
    }

Now that you already have a Data Transfer Object (DTO) we’re going to add a domain event. And to facilitate the process we will use an accelerator of the DevPrime CLI.
dp add domainevent DeliveryGetOrder -agg Delivery

After confirming locate the file “DeliveryGetOrderEventHandler.cs” in the /src/Core/Application/EventHandlers/Delivery folder and implememte the query to the external service using Adapter Services by the command “Dp.Services.HTTP.DpGet”.

Our goal in this example will be to evaluate the return “result”. In case of success with the code “200” we will return the order value.

using Application.EventHandlers.Delivery.Model;
namespace Application.EventHandlers.Delivery;


public class DeliveryGetOrderEventHandler : EventHandler<DeliveryGetOrder, IDeliveryState>
{
    public DeliveryGetOrderEventHandler(IDeliveryState state, IDp dp) : base(state, dp)
    {
    }

    public override dynamic Handle(DeliveryGetOrder domainEvent)
    {
        // Aggregate Root
        var delivery = domainEvent.Get<Domain.Aggregates.Delivery.Delivery>();

        // External http request using Services Adapter
        var url = $"https://localhost:5001/v1/order/{delivery.OrderID}";

        // Yype dynamic
        var result = Dp.Services.HTTP.DpGet<OrderCreated>(url);

        //Analysis result
        if (result.Status.Equals(200))
            return result.Total;
        else
            return null;
    }
}

The Services Adapter’s example ness will access a DevPrime-based API via HTTP and using the specific “DpGet” command for DevPrime-based API’s. By using DpGet it already identifies the result and converts it to the “OrderCreated” format by automating the process.

Adding a DomainEvent in Aggretate

The last step is to modify the “Add()” method present in the Aggretate root “Delivery”. Add the implementation to issue the “DeliveryGetOrder()” event that will be intercepted by the handler “DeliveryGetOrderEventHandler” implemented earlier.
code src/Core/Domain/Aggregates/Delivery/Delivery.cs

public virtual void Add()
{
          Dp.Pipeline(Execute: () =>
          {
            ValidFields();
              ID = Guid.NewGuid();

              var ordertotal = Dp.ProcessEvent(new DeliveryGetOrder());
              if (ordertotal != null)
              {

                  Total = ordertotal;
                  Dp.ProcessEvent(new DeliveryCreated());
              }
              else
              {
                  throw new PublicException("Can not confirm order");
              }            
          });
}

If we can get the order value we will update the aggregate and issue the event “DeliveryCreated” by propagating the business fact. If not we will issue a PublicException
that will return to the caller of this API a process failure information.

Demonstrating the Delivery Scenario

To start the scenario demonstration it is necessary to run the microservices “ms-order” and “ms-delivery” at the same time. As they are in different doors we will be able to demonstrate the scenery with tranquility.

Microservices: Order

  1. Open the browser in the “ms-order” microservices API on [http://localhost:5000 or https://localhost:5001]
  2. Post the ‘/v1/order’ API by filling in the customerName and total.
{
  "customerName": "Bill",
  "customerTaxID": "string",
  "itens": [
    {
      "description": "string",
      "amount": 0,
      "sku": "string",
      "price": 0
    }
  ],
  "total": 1000
}
  1. Get the ‘/v1/order’ API and find the order code ‘id’

Microservices: Delivery

  1. Open the browser in the “ms-order” microservices API on [http://localhost:5002 or https://localhost:5003]
  2. Post the ‘/v1/delivery’ API informing the order code under ‘orderID’.
{
  "started": "2022-03-07T17:54:41.920Z",
  "finished": "2022-03-07T17:54:41.920Z",
  "orderID": "",
  "total": 0
}
  1. Microservices “ms-delivery” will query the API order using Adapter Services and return the total order value. The next step is to create a record in the delivery microservice and issue an event in stream
{
  "success": true
}

DevPrime Version

You can also track the ‘GET’ request from the microservice side

DevPrime Version

  1. In this new scenario generate a GUID orderID and post the ‘/v1/delivery’ API.
{
  "started": "2022-03-07T17:54:41.920Z",
  "finished": "2022-03-07T17:54:41.920Z",
  "orderID": "a316f224-c8fd-4d4d-8495-600f9fea7aaa",
  "total": 0
}
  1. When querying the “Order” microservice on a nonexistent order the Delivery API returns an error.
{
  "success": false,
  "error": {
    "type": "Public",
    "trace": "05d359f0-f99a-4f63-8f89-0ac87ac36edd",
    "exceptions": [
      "Can not confirm order"
    ]
  }
}

Congratulations, i’m 🚀🚀🚀 sorry.

Last modified March 10, 2022 (615ec2b)