How-To: Use output bindings to interface with external resources

Invoke external systems with output bindings

With output bindings, you can invoke external resources. An optional payload and metadata can be sent with the invocation request.

Diagram showing bindings of example service

This guide uses a Kafka binding as an example. You can find your preferred binding spec from the list of bindings components. In this guide:

  1. The example invokes the /binding endpoint with checkout, the name of the binding to invoke.
  2. The payload goes inside the mandatory data field, and can be any JSON serializable value.
  3. The operation field tells the binding what action it needs to take. For example, the Kafka binding supports the create operation.

Note

If you haven’t already, try out the bindings quickstart for a quick walk-through on how to use the bindings API.

Create a binding

Create a binding.yaml file and save to a components sub-folder in your application directory.

Create a new binding component named checkout. Within the metadata section, configure the following Kafka-related properties:

  • The topic to which you’ll publish the message
  • The broker

When creating the binding component, specify the supported direction of the binding.

Use the --resources-path flag with dapr run to point to your custom resources directory.

  1. apiVersion: dapr.io/v1alpha1
  2. kind: Component
  3. metadata:
  4. name: checkout
  5. spec:
  6. type: bindings.kafka
  7. version: v1
  8. metadata:
  9. # Kafka broker connection setting
  10. - name: brokers
  11. value: localhost:9092
  12. # consumer configuration: topic and consumer group
  13. - name: topics
  14. value: sample
  15. - name: consumerGroup
  16. value: group1
  17. # publisher configuration: topic
  18. - name: publishTopic
  19. value: sample
  20. - name: authRequired
  21. value: false
  22. - name: direction
  23. value: output

To deploy the following binding.yaml file into a Kubernetes cluster, run kubectl apply -f binding.yaml.

  1. apiVersion: dapr.io/v1alpha1
  2. kind: Component
  3. metadata:
  4. name: checkout
  5. spec:
  6. type: bindings.kafka
  7. version: v1
  8. metadata:
  9. # Kafka broker connection setting
  10. - name: brokers
  11. value: localhost:9092
  12. # consumer configuration: topic and consumer group
  13. - name: topics
  14. value: sample
  15. - name: consumerGroup
  16. value: group1
  17. # publisher configuration: topic
  18. - name: publishTopic
  19. value: sample
  20. - name: authRequired
  21. value: false
  22. - name: direction
  23. value: output

Send an event (output binding)

The code examples below leverage Dapr SDKs to invoke the output bindings endpoint on a running Dapr instance.

  1. //dependencies
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Net.Http;
  5. using System.Net.Http.Headers;
  6. using System.Threading.Tasks;
  7. using Dapr.Client;
  8. using Microsoft.AspNetCore.Mvc;
  9. using System.Threading;
  10. //code
  11. namespace EventService
  12. {
  13. class Program
  14. {
  15. static async Task Main(string[] args)
  16. {
  17. string BINDING_NAME = "checkout";
  18. string BINDING_OPERATION = "create";
  19. while(true)
  20. {
  21. System.Threading.Thread.Sleep(5000);
  22. Random random = new Random();
  23. int orderId = random.Next(1,1000);
  24. using var client = new DaprClientBuilder().Build();
  25. //Using Dapr SDK to invoke output binding
  26. await client.InvokeBindingAsync(BINDING_NAME, BINDING_OPERATION, orderId);
  27. Console.WriteLine("Sending message: " + orderId);
  28. }
  29. }
  30. }
  31. }
  1. //dependencies
  2. import io.dapr.client.DaprClient;
  3. import io.dapr.client.DaprClientBuilder;
  4. import io.dapr.client.domain.HttpExtension;
  5. import org.springframework.boot.autoconfigure.SpringBootApplication;
  6. import org.slf4j.Logger;
  7. import org.slf4j.LoggerFactory;
  8. import java.util.Random;
  9. import java.util.concurrent.TimeUnit;
  10. //code
  11. @SpringBootApplication
  12. public class OrderProcessingServiceApplication {
  13. private static final Logger log = LoggerFactory.getLogger(OrderProcessingServiceApplication.class);
  14. public static void main(String[] args) throws InterruptedException{
  15. String BINDING_NAME = "checkout";
  16. String BINDING_OPERATION = "create";
  17. while(true) {
  18. TimeUnit.MILLISECONDS.sleep(5000);
  19. Random random = new Random();
  20. int orderId = random.nextInt(1000-1) + 1;
  21. DaprClient client = new DaprClientBuilder().build();
  22. //Using Dapr SDK to invoke output binding
  23. client.invokeBinding(BINDING_NAME, BINDING_OPERATION, orderId).block();
  24. log.info("Sending message: " + orderId);
  25. }
  26. }
  27. }
  1. #dependencies
  2. import random
  3. from time import sleep
  4. import requests
  5. import logging
  6. import json
  7. from dapr.clients import DaprClient
  8. #code
  9. logging.basicConfig(level = logging.INFO)
  10. BINDING_NAME = 'checkout'
  11. BINDING_OPERATION = 'create'
  12. while True:
  13. sleep(random.randrange(50, 5000) / 1000)
  14. orderId = random.randint(1, 1000)
  15. with DaprClient() as client:
  16. #Using Dapr SDK to invoke output binding
  17. resp = client.invoke_binding(BINDING_NAME, BINDING_OPERATION, json.dumps(orderId))
  18. logging.basicConfig(level = logging.INFO)
  19. logging.info('Sending message: ' + str(orderId))
  1. //dependencies
  2. import (
  3. "context"
  4. "log"
  5. "math/rand"
  6. "time"
  7. "strconv"
  8. dapr "github.com/dapr/go-sdk/client"
  9. )
  10. //code
  11. func main() {
  12. BINDING_NAME := "checkout";
  13. BINDING_OPERATION := "create";
  14. for i := 0; i < 10; i++ {
  15. time.Sleep(5000)
  16. orderId := rand.Intn(1000-1) + 1
  17. client, err := dapr.NewClient()
  18. if err != nil {
  19. panic(err)
  20. }
  21. defer client.Close()
  22. ctx := context.Background()
  23. //Using Dapr SDK to invoke output binding
  24. in := &dapr.InvokeBindingRequest{ Name: BINDING_NAME, Operation: BINDING_OPERATION , Data: []byte(strconv.Itoa(orderId))}
  25. err = client.InvokeOutputBinding(ctx, in)
  26. log.Println("Sending message: " + strconv.Itoa(orderId))
  27. }
  28. }
  1. //dependencies
  2. import { DaprClient, CommunicationProtocolEnum } from "@dapr/dapr";
  3. //code
  4. const daprHost = "127.0.0.1";
  5. (async function () {
  6. for (var i = 0; i < 10; i++) {
  7. await sleep(2000);
  8. const orderId = Math.floor(Math.random() * (1000 - 1) + 1);
  9. try {
  10. await sendOrder(orderId)
  11. } catch (err) {
  12. console.error(e);
  13. process.exit(1);
  14. }
  15. }
  16. })();
  17. async function sendOrder(orderId) {
  18. const BINDING_NAME = "checkout";
  19. const BINDING_OPERATION = "create";
  20. const client = new DaprClient({
  21. daprHost,
  22. daprPort: process.env.DAPR_HTTP_PORT,
  23. communicationProtocol: CommunicationProtocolEnum.HTTP,
  24. });
  25. //Using Dapr SDK to invoke output binding
  26. const result = await client.binding.send(BINDING_NAME, BINDING_OPERATION, orderId);
  27. console.log("Sending message: " + orderId);
  28. }
  29. function sleep(ms) {
  30. return new Promise(resolve => setTimeout(resolve, ms));
  31. }

You can also invoke the output bindings endpoint using HTTP:

  1. curl -X POST -H 'Content-Type: application/json' http://localhost:3601/v1.0/bindings/checkout -d '{ "data": 100, "operation": "create" }'

Watch this video on how to use bi-directional output bindings.

References

Last modified October 11, 2024: Fixed typo (#4389) (fe17926)