Dapr Quickstarts and Tutorials

repository·master·Indexed 22 days ago

https://github.com/dapr/quickstarts

A collection of Dapr Quickstarts and Tutorials for implementing building blocks such as Pub/Sub, State Management, Workflows, Actors, and Bindings. Includes practical examples using various language SDKs (C#, Go, Java, Python) and integrations with external systems like PostgreSQL.

Tokens
99.4K
Snippets
376
Records
442
Agent score
75%

What's inside dapr-quickstarts

  1. Overview of the Distributed Calculator Quickstart

    master

    The Distributed Calculator quickstart demonstrates Dapr's method invocation and state persistence capabilities. It uses a multi-language architecture where different mathematical operations are handled by different services:

    • Addition: Go (using mux)
    • Multiplication: Python (using flask)
    • Division: Node (using Express)
    • Subtraction: .NET Core
    • Frontend: React (consisting of a server and a client)

    The frontend application interacts with these services and persists state in a local Redis state store.

  2. Overview of Dapr Pub-Sub Quickstart

    master

    This quickstart demonstrates the publish-subscribe pattern using Dapr. It involves a publisher microservice that generates messages for specific topics and multiple subscriber microservices that listen for those topics.

    Architecture Components:

    • Publisher: A React front-end message generator.
    • Subscribers: Node.js, Python, and C# microservices.
    • Message Bus: Dapr uses pluggable message buses; this quickstart uses Redis Streams (requires Redis version 5 or greater).
    • Message Format: Messages are delivered in a Cloud Events compliant envelope.

    This pattern allows for decoupled communication where the publisher does not need to know who the subscribers are.

  3. Use the Dapr Configuration API via HTTP

    master

    The Dapr Configuration API allows microservices to retrieve key/value pairs (such as app IDs, partition keys, or database names) from a configuration store and subscribe to real-time updates when those values change.

    This specific quickstart demonstrates how a Go service (order-processor) interacts with the Configuration API using raw HTTP requests rather than a dedicated SDK. For production use, using the Dapr Client SDK is recommended.

  4. How to interact with Dapr Actors using ActorProxy

    master

    In the Dapr .NET SDK, you interact with actors using an ActorProxy. You provide a unique ActorId, the actor type name, and the interface that defines the actor's capabilities. If an actor with the specified ID does not exist, Dapr will create it upon the first call.

    Actors are re-entrant and maintain state across calls, which can be retrieved using methods defined in the interface (e.g., GetDataAsync()).

    // Actor Ids and types
    var deviceId1 = "1";
    var smokeDetectorActorType = "SmokeDetectorActor";
    
    // An ActorId uniquely identifies an actor instance
    var deviceActorId1 = new ActorId(deviceId1);
    
    // Create the local proxy using the interface implemented by the service
    var proxySmartDevice1 = ActorProxy.Create<ISmartDevice>(deviceActorId1, smokeDetectorActorType);
    
    // Use the proxy to call methods on the actor
    var deviceData1 = new SmartDeviceData() { Location = "First Floor", Status = "Ready" };
    var setDataResponse1 = await proxySmartDevice1.SetDataAsync(deviceData1);
  5. How Dapr Pub-Sub subscription works

    master

    To subscribe to topics using Dapr, your application must expose a GET endpoint at /dapr/subscribe. This endpoint returns a JSON array of subscription objects. Each object defines the pubsubname (the name of the Dapr pubsub component), the topic to listen to, and the route (the endpoint in your app that will handle the incoming messages).

    When Dapr starts or is deployed, it calls this endpoint to discover which topics the service is interested in. Once subscribed, Dapr will send messages to the specified route via a POST request.

    // Example Node.js subscription endpoint
    app.get('/dapr/subscribe', (_req, res) => {
        res.json([
            {
                pubsubname: "pubsub",
                topic: "A",
                route: "A"
            }
        ]);
    });
  6. How Dapr enables service invocation and state management

    master

    This tutorial demonstrates three core Dapr capabilities:

    1. Polyglot Programming: Services are written in different languages (e.g., JavaScript, Python, .NET) and communicate via Dapr sidecars without needing language-specific Dapr dependencies.
    2. Service Invocation: Instead of calling a service's IP address directly, you call the local Dapr sidecar using a consistent URL syntax. Dapr handles service discovery (e.g., via Kubernetes DNS) to route the request to the correct destination.
    3. Simplified State Management: Dapr provides a layer of indirection for state. Applications interact with a standard HTTP endpoint provided by the sidecar, removing the need for the application to manage specific state provider configurations, retry logic, or connection strings.

    Service Invocation URL Pattern: http://localhost:${daprPort}/v1.0/invoke/${appId}/method/${methodName}

    State Management URL Pattern: http://localhost:${daprPort}/v1.0/state/${stateStoreName}

    // Service Invocation Example
    const daprUrl = `http://localhost:${daprPort}/v1.0/invoke`;
    
    // Invoking the 'add' method on 'addapp'
    await axios.post(`${daprUrl}/addapp/method/add`, req.body);
    
    // Invoking the 'subtract' method on 'subtractapp'
    await axios.post(`${daprUrl}/subtractapp/method/subtract`, req.body);
    
    // State Management Example
    const stateUrl = `http://localhost:${daprPort}/v1.0/state/${stateStoreName}`;
  7. Invoke a service via Dapr Service Invocation

    master

    Dapr allows applications to communicate with each other using service invocation without knowing the destination's hostname or port. You invoke a service by sending an HTTP request to the Dapr sidecar using the following URL pattern:

    http://localhost:{DAPR_HTTP_PORT}/v1.0/invoke/{app-id}/method/{method-name}

    In the Hello World example, the Python app invokes the Node app (nodeapp) by calling the neworder method: http://localhost:{DAPR_HTTP_PORT}/v1.0/invoke/nodeapp/method/neworder

    The {app-id} in the URL must match the --app-id used when starting the target service.

    # Example of constructing a Dapr invocation URL in Python
    dapr_port = os.getenv("DAPR_HTTP_PORT", 3500)
    dapr_url = "http://localhost:{}/v1.0/invoke/nodeapp/method/neworder".format(dapr_port)
    
    # Sending the request
    response = requests.post(dapr_url, json=message)
  8. Understand Dapr resiliency policies

    master

    Dapr allows you to define fault tolerance policies to handle system failures. These policies include:

    • Retries/Back-offs: Automatically retrying failed requests with configurable delay strategies.
    • Timeouts: Setting limits on how long a request can take before being aborted.
    • Circuit Breakers: Preventing requests from being sent to a failing service to allow it time to recover.

    Resiliency policies are defined via a resiliency spec (YAML). These specs are stored in the same location as your Dapr component specifications and are applied automatically when the Dapr sidecar starts. The sidecar is responsible for intercepting Dapr API calls and applying these policies.

  9. How the Secrets API works in the Node.js tutorial

    master

    The tutorial uses an Express.js application to interact with the Dapr Secrets API.

    Key Variables

    • SECRET_STORE: An environment variable that determines which Dapr component to query. For local development, this is set to localsecretstore. In Kubernetes, it is typically set to kubernetes.
    • secretName: The specific key to retrieve from the store (e.g., mysecret).

    API Interaction Pattern

    The application constructs a URL to call the Dapr sidecar's secrets endpoint: {{secretsUrl}}/{{secretStoreName}}/{{secretName}}?metadata.namespace=default

    Example logic used in the getsecret handler:

    1. Fetch the secret from the Dapr sidecar via HTTP.
    2. Parse the JSON response.
    3. Convert the secret value to a Buffer and then to a Base64 encoded string for display.
    const daprPort = process.env.DAPR_HTTP_PORT || 3500;
    const secretStoreName = process.env.SECRET_STORE; 
    const secretName = 'mysecret';
    
    // Inside the handler:
    const url = `${secretsUrl}/${secretStoreName}/${secretName}?metadata.namespace=default`;
    fetch(url)
      .then(res => res.json())
      .then(json => {
          let secretBuffer = new Buffer(json["mysecret"])
          let encodedSecret = secretBuffer.toString('base64')
          return res.send(encodedSecret)
      });
  10. How to use Actor Reminders

    master

    Actors can schedule tasks to run at a specific time in the future using RegisterReminderAsync. This is useful for recurring tasks or delayed actions (e.g., clearing an alarm state after a timeout).

    In the provided example, the ControllerActor registers a reminder named "AlarmRefreshReminder" to trigger every 15 seconds to refresh and clear alarm states.

    public async Task TriggerAlarmForAllDetectors()
    {
        // ... logic to trigger alarms ...
    
        // Register a reminder to refresh and clear alarm state every 15 seconds
        await this.RegisterReminderAsync("AlarmRefreshReminder", null, TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(15));
    }
  11. How Dapr Bindings work

    master

    Dapr Bindings allow microservices to connect to external resources (like Kafka, RabbitMQ, or AWS S3) without needing to know the specific implementation details or connection strings of those resources. Instead, services interact with the Dapr sidecar using the Dapr API.

    There are two primary types of bindings used in this quickstart:

    1. Input Bindings: The Dapr sidecar receives messages from an external resource (e.g., Kafka) and pushes them to the application.
    2. Output Bindings: The application sends data to the Dapr sidecar, which then pushes that data to an external resource (e.g., Kafka).

    In this specific example, a Python microservice uses an output binding to push messages into Kafka, and a Node.js microservice uses an input binding to receive those messages from Kafka.