Traditionally enterprise applications in complex environments make usage of Enterprise Service Bus.The bus integration pattern provided bu an ESB has typically focused Service Oriented Architecture. By using of ESB, services can exchange message if they support some kind of message API.This concept decouples service from each other and enables cross technology and cross-platform message exchange.With increasing popularity of cloud technologies and microservices, complexity of requirements for distributed systems also increased. When thinking about general service invocation DAPR solves following complex requirements:
- Service Discovery
Services can invoke each other without knowing the location of the destination service. In the context of DAPR, one service or application will send the message to the DAPR endpoint. Because DAPR runtime tracks instantiation of all services, it is able to serve the request and route it to the correct destination. - Sidecar Architecture
DAPR runtime provides a service discovery and a Sidecar architecture. This means, the DAPR runtime acts as a proxy for the system participant, which invokes some service. In contrast the DAPR runtime acts as a reverse proxy for service, which receives the request. As long service expose message Web Service APIs, this architecture is not necessary and this requirement can be solved by any message broker.
However, many enterprise services provide RPC Web Service API (i.E.; Direct request response). With Sidecar architecture it is possible to establish the communication between services by using different protocols and web service API styles.
For example, Service S1 can talk to Service S2 via gRPC even if Service S2 supports HTTP/S REST only.Moreover, all WRITE service operations (create customer, change order, etc) can be triggered by events, even if operations are implemented as pure REST operations. If you ever heard about CQRS the DAPR gives a sort of it for free (WRITE operations triggered as events and READ operations invoked by RPC = gRPC or REST).
This article describes a sample REST RoutingSample service, which implements a simple banking application in ASP.NET core.
The service provides following operations:
- balance
- withdraw
- deposite
The service is a typical HTTP/S REST service. However, by using dapr, another application can invoke an operation on this service by using not only REST.
Following sample demonstrates how to use the gRPC with Dapr .NET SDK to invoke REST service operations.
Invoking REST GET operation
Operation balance is a GET-operation mapped as (see startup.cs in the RoutingService):
endpoints.MapGet("{id}", Balance);
It can be invoked via HTTTP/S by using following url:
curl -X GET http://127.0.0.1:5000/17
If you are developing the .NET client and want to invoke this operation via HTTP/S, you can also use HttpClient API.
The dapr supports out-of-the-box invokation of the service operation via gRPC.
To demonstrate this, take a look on the method InvokeBalanceServiceOperationAsync.
internal static async Task
InvokeBalanceServiceOperationAsync(DaprClient client)
{
// Add the verb to metadata if the method is other than a POST
var metaData = new Dictionary<string, string>();
metaData.Add("http.verb", "GET");
// Invokes a GET method named "hello" that takes input
// of type "MyData" and returns a string.
var res = await client.InvokeMethodAsync<object>
("routing", "17", metaData);
}
Invoking REST POST operation
Second operation withdraw can be invoked by HTTP/S POST request, but also triggered as a cloud event by publishing the event to the topic with name 'withdraw'.
To enable this, the operation is mapped as:
endpoints.MapPost("withdraw", Withdraw).WithTopic("withdraw");
and it can also be invoked (triggered) by following url:
curl -X POST http://127.0.0.1:5000/withdraw -H "Content-Type: application/json" -d "{ \"id\": \"17\", \"amount\": 1 }"
The method InvokeWithdrawServiceOperationAsync demonstrates how to use DAPR .NET SDK to invoke a REST/POST operation via gRPC.
internal static async Task
InvokeWithdrawServiceOperationAsync(DaprClient client)
{
var data = new { id = "17", amount = (decimal)10, };
// Add the verb to metadata if the method is other than a POST
var metaData = new Dictionary<string, string>();
metaData.Add("http.verb", "POST");
// Invokes a POST method named "Withdraw" that
// takes input of type "Transaction" as define in the RoutingSample.
await client.InvokeMethodAsync<object>
("routing", "Withdraw", data, metaData);
}
Because, the same operation subscribes events on the withdraw topic, it can be invoked by event:
dapr publish -t withdraw -p '{"id": "17", "amount": 15 }'
Invoking REST POST with PUB/SUB operation
Operation deposite can be invoked by HTTP/S POST request and also triggered as a cloud event by publishing the event to the topic with name 'deposite'.
It is mapped as:
endpoints.MapPost("deposit", Withdraw).WithTopic("deposit");
You can also use a dapr cli to publish the event to invoke te operation deposit:
dapr publish -t deposit -p '{"id": "17", "deposit": 15 }'
Following code-snipet demonstrates how to publish an event to the dapr runtime, which triggers the REST operation 'deposit'.
internal static async Task PublishDepositeEventToRoutingSampleAsync(DaprClient client)
{
var eventData = new { id = "17", amount = (decimal)10, };
await client.PublishEventAsync("deposit", eventData);
Console.WriteLine("Published deposit event!");
}