APIs for building secure & reliable microservices

dapr allows you to build state-of-the-art apps in half the time and never worry about missing a deadline or delivering insecure & unreliable code

Get started
APIs for every software pattern. no more boilerplate code
proven multi-cloud portability with zero code change
built-in security, reliability,
and observability

Diagrid is trusted by:

APIs to build web-scale applications in days

Author workflows in code to automate complex business processes that are stateful, durable, and long-running.

  • Automatic handling of failures and errors

  • Support for task chaining, fan-out/fan-in, monitor and external system interaction

  • Workflow state can be stored in your database

create workflow
public class MoneyTransferWorkflow : Workflow<MoneyTransferParams, bool>
{
    public override async Task<bool> RunAsync(WorkflowContext context, MoneyTransferParams input)
    {
        // withdraw money from account
        await context.CallActivityAsync(nameof(WithdrawActivity), new WithdrawParams(input.fromAccount, input.amount));
        try
        {
            // deposit money in target account
            await context.CallActivityAsync(nameof(DepositActivity), new DepositParams(input.toAccount, input.amount));
        }
        catch (System.Exception)
        {
            // in case of error deposit back the money in the original account
            await context.CallActivityAsync(nameof(DepositActivity), new DepositParams(input.fromAccount, input.amount));
        }
        return true;
    }
}
def money_transfer_workflow(ctx: DaprWorkflowContext, input: MoneyTransferParams):
    # withdraw money from account
    yield ctx.call_activity(withdraw, input=WithdrawParams(input.fromAccount, input.amount))
    try:
        # deposit money in target account
        yield ctx.call_activity(deposit, input=DepositParams(input.toAccount, input.amount))
    except Exception as e:
        # in case of error deposit back the money in the original account
        yield ctx.call_activity(deposit, input=DepositParams(input.fromAccount, input.amount))
const moneyTransferWorkflow = async function*(ctx, input) {
    // withdraw money from account
    yield ctx.callActivity(withdrawActivity, { account: input.fromAccount, amount: input.amount });
    try {
        // deposit money in target account
        yield ctx.callActivity(depositActivity, { account: input.toAccount, amount: input.amount });
    } catch (error) {
        // in case of error deposit back the money in the original account
        yield ctx.callActivity(depositActivity, { account: input.fromAccount, amount: input.amount });
    }
}
 
 	
public class MoneyTransferWorkflow extends Workflow {
  @Override
  public WorkflowStub create() {
    return ctx -> {
      MoneyTransferParams input = ctx.getInput(MoneyTransferParams.class);

      // withdraw money from account
      ctx.callActivity(WithdrawActivity.class.getName(), new WithdrawParams(input.fromAccount, input.amount)).await();
      try {
        // deposit money in target account
        ctx.callActivity(DepositActivity.class.getName(), new DepositParams(input.toAccount, input.amount)).await();
      } catch (Exception e) {
        // in case of error deposit back the money in the original account
        ctx.callActivity(DepositActivity.class.getName(), new DepositParams(input.fromAccount, input.amount)).await();
      }
    };
  }
}
func MoneyTransferWorkflow(ctx *workflow.WorkflowContext) (any, error) {
        var input MoneyTransferParams
        if err := ctx.GetInput(&input); err != nil {
                return nil, err
        }

        // withdraw money from account
        if err := ctx.CallActivity(Withdraw, workflow.ActivityInput(WithdrawParams{
                Account: input.FromAccount,
                Amount:  input.Amount,
        })).Await(nil); err != nil {
                return nil, err
        }

        // deposit money in target account
        if err := ctx.CallActivity(Deposit, workflow.ActivityInput(DepositParams{
                Account: input.ToAccount,
                Amount:  input.Amount,
        })).Await(nil); err != nil {
                // in case of error deposit back the money in the original account
                return nil, ctx.CallActivity(Deposit, workflow.ActivityInput(DepositParams{
                        Account: input.FromAccount,
                        Amount:  input.Amount,
                })).Await(nil)
        }
        return nil, nil
}

Create event-driven apps that scale to millions of events/sec. Integrates with dozens of message brokers.

  • Configurable push/pull eventing

  • At-least-once guaranteed message delivery

  • Automatic CloudEvents support

  • Bulk message delivery

publish message
using Dapr.Client;

var client = new DaprClientBuilder().Build();

// Publish message
await client.PublishEventAsync(“my-pubsub”, "my-topic", “my-message”);
from dapr.clients import DaprClient;

with DaprClient() as d:
  result = d.publish_event(
    pubsub_name = "my-pubsub",
    topic_name = 'orders',
    data = `{ "orderId": 1 }`,
    data_content_type = 'application/json')
import { DaprClient, CommunicationProtocolEnum } from "@dapr/dapr";

(async () => {
  const client = new DaprClient({ communicationProtocol: CommunicationProtocolEnum.HTTP });

  await client.pubsub.publish("my-pubsub", "orders", {"orderId":"1"});
})()
import io.dapr.client.DaprClient;
import io.dapr.client.DaprClientBuilder;
import io.dapr.client.domain.Metadata;

import static java.util.Collections.singletonMap;

DaprClient client = new DaprClientBuilder().build()
client.publishEvent("pubsub", "orders", "{\"orderId\":\"1\"}", singletonMap(Metadata.TTL_IN_SECONDS, "600")).block();
package main

import (
        "context"
        "fmt"

        dapr "github.com/dapr/go-sdk/client"
)

func main() {
        client, err := dapr.NewClient()
        if err != nil {
                panic(fmt.Errorf("error creating connection to catalyst: %w", err))
        }
        defer client.Close()

        if err := client.PublishEvent(context.TODO(), "pubsub", "{topic-name}",
                []byte(`{"key":"value"}`)); err != nil {
                panic(fmt.Errorf("error publishing event: %w", err))
        }
}

Connect apps running on any cloud platform and across any region.

  • Zero networking configuration

  • Service discovery

  • End-to-end mTLS & authorization

connect app
using Dapr.Client;

var client = new DaprClientBuilder().Build();
var httpClient = DaprClient.CreateInvokeHttpClient(“my-target-app”);
httpClient.DefaultRequestHeaders.Add("dapr-api-token", “my-api-token”);

var response = await httpClient.PostAsync("/target-method", "{\"data\":\"my-data\"}");
from dapr.clients import DaprClient;

headers = { 'dapr-app-id': ‘my-target-app’, 'content-type': 'application/json'}
result = requests.post(
  url = '/orders',
  data =‘{
\"data\":\"my-data\"}’,
        headers = headers)
import axios from "axios";

async function main() {
  // Adding app id as part of the header
  let axiosConfig = {
    headers: {
        "dapr-app-id": "order-processor"
    }
  };
  
  const order = { orderId: 1 };
    const res = await axios.post(`/orders`, order , axiosConfig);
}

main().catch(e => console.error(e))
private static final HttpClient httpClient = HttpClient.newBuilder()
                        .version(HttpClient.Version.HTTP_2)
                        .connectTimeout(Duration.ofSeconds(10))
                        .build();

    private static final String DAPR_HTTP_PORT = System.getenv().getOrDefault("DAPR_HTTP_PORT", "3500");

    public static void main(String[] args) throws InterruptedException, IOException {
                String dapr_url = "http://localhost:" + DAPR_HTTP_PORT + "/orders";
                int orderId = 1;
                JSONObject obj = new JSONObject();
                obj.put("orderId", orderId);

                HttpRequest request = HttpRequest.newBuilder()
                                .POST(HttpRequest.BodyPublishers.ofString(obj.toString()))
                                .uri(URI.create(dapr_url))
                                .header("Content-Type", "application/json")
                                .header("dapr-app-id", "order-processor")
                                .build();

                HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());   
                System.out.println("Order passed: "+ orderId);
                TimeUnit.MILLISECONDS.sleep(1000);
    }
import (
        "context"
        "fmt"
        "net/http"

        dapr "github.com/dapr/go-sdk/client"
)

func main() {
        client, err := dapr.NewClient()
        if err != nil {
                panic(fmt.Errorf("error creating connection to catalyst: %w", err))
        }
        defer client.Close()

        order := `{"orderId":` + strconv.Itoa(i) + "}"
        req, err := http.NewRequest("POST", "/orders", strings.NewReader(order))
        if err != nil {
                panic()
        }
        req.Header.Add("dapr-app-id", "order-processor")

        response, err := client.Do(req)
        if err != nil {
                panic()
        }

Create CRUD applications with key/value state. Integrates with dozens of databases.

  • Data isolation for multi-tenancy

  • Configurable concurrency (first-write-wins, last-write-wins)

  • Configurable consistency (strong,  eventual)

  • Caching support with TTL

connect database
using Dapr.Client;

var client = new DaprClientBuilder().Build();
await client.SaveStateAsync(“my-database”, “1”, “myvalue”);
from dapr.clients import DaprClient

with DaprClient() as d:
    order = {'orderId': "1", "name": "lightsaber (real)"}
    client.save_state("my-database", "1", str(order))
import { CommunicationProtocolEnum, DaprClient } from "@dapr/dapr"

const order = { orderId: "1" }
const state = [
    {
        key: order.orderId,
        value: order,
        options: {
            consistency: "strong",
            concurrency: "first-write-wins"
        }
    }
]

const client = new DaprClient({ communicationProtocol: CommunicationProtocolEnum.HTTP });
await client.state.save("my-database", state)
import io.dapr.client.DaprClient;
import io.dapr.client.DaprClientBuilder;

DaprClient client = new DaprClientBuilder().build();
               
Order order = new Order();
order.setOrderId(orderId);

client.saveState("my-database", String.valueOf(orderId), order).block();
package main

import (
        "context"
        "fmt"

        dapr "github.com/dapr/go-sdk/client"
)

func main() {
        client, err := dapr.NewClient()
        if err != nil {
                panic()
        }
        defer client.Close()

        if err := err := client.SaveState(context.Background(), "my-database, "order", []byte("value), nil); err != nil {
                panic()
        }
}

Interact with external systems via triggers and outgoing calls.

  • Integrations with dozens of third party services

  • Authenticate calls to/from external systems

Connect System
using Dapr.Client;

var client = new DaprClientBuilder().Build();
await client.InvokeBindingAsync(“my-binding”, “create”, “my-data”);
from dapr.clients import DaprClient

with DaprClient() as d:
    resp = d.invoke_binding(
      binding_name="my-binding", 
      operation="create", data="100")
import { DaprClient, CommunicationProtocolEnum } from "@dapr/dapr";

(async () => {
  const client = new DaprClient({ communicationProtocol: CommunicationProtocolEnum.HTTP });
  await client.binding.send("my-binding", "create", 100);
})()
import io.dapr.client.DaprClient;
import io.dapr.client.DaprClientBuilder;

DaprClient client = new DaprClientBuilder().build()
client.invokeBinding("my-binding", "create", "100").block();
package main

import (
        "context"
        "fmt"

        dapr "github.com/dapr/go-sdk/client"
)

func main() {
        client, err := dapr.NewClient()
        if err != nil {
                panic(fmt.Errorf("error creating connection to catalyst: %w", err))
        }
        defer client.Close()

        err = client.InvokeOutputBinding(context.TODO(),
                &dapr.InvokeBindingRequest{
                        Name:      "my-binding",
                        Operation: "create",
                        Data:      []byte(`100`),
                })
        if err != nil {
                panic(err)
        }
}
Workflow
Publish / Subscribe
Service Invocation
State Management
Bindings

Author workflows in code to automate complex business processes that are stateful, durable, and long-running.

  • Automatic handling of failures and errors

  • Support for task chaining, fan-out/fan-in, monitor and external system interaction

  • Workflow state can be stored in your database

create workflow
{
    public override async Task<OrderResult> RunAsync(WorkflowContext context, OrderPayload order)
    {
        string orderId = context.InstanceId;

        // Notify the user that an order has come through
        await context.CallActivityAsync(
            nameof(NotifyActivity),
            new Notification($"Received order {orderId} for {order.Quantity} {order.Name} at ${order.TotalCost}"));

        string requestId = context.InstanceId;

        // Determine if there is enough of the item available for purchase by checking the inventory
        InventoryResult result = await context.CallActivityAsync<InventoryResult>(
            nameof(ReserveInventoryActivity),
            new InventoryRequest(RequestId: orderId, order.Name, order.Quantity));
        
        // If there is insufficient inventory, fail and let the user know 
        if (!result.Success)
        {
            // End the workflow here since we don't have sufficient inventory
            await context.CallActivityAsync(
                nameof(NotifyActivity),
                new Notification($"Insufficient inventory for {order.Name}"));
            return new OrderResult(Processed: false);
        }

        // There is enough inventory available so the user can purchase the item(s). Process their payment
        await context.CallActivityAsync(
            nameof(ProcessPaymentActivity),
            new PaymentRequest(RequestId: orderId, order.Name, order.Quantity, order.TotalCost));

        try
        {
            // There is enough inventory available so the user can purchase the item(s). Process their payment
            await context.CallActivityAsync(
                nameof(UpdateInventoryActivity),
                new PaymentRequest(RequestId: orderId, order.Name, order.Quantity, order.TotalCost));                
        }
        catch (TaskFailedException)
        {
            // Let them know their payment was processed
            await context.CallActivityAsync(
                nameof(NotifyActivity),
                new Notification($"Order {orderId} Failed! You are now getting a refund"));
            return new OrderResult(Processed: false);
        }

        // Let them know their payment was processed
        await context.CallActivityAsync(
            nameof(NotifyActivity),
            new Notification($"Order {orderId} has completed!"));

        // End the workflow with a success result
        return new OrderResult(Processed: true);
    }
}
def main(self):
    item_name = "lightsaber"
    order_quantity = 100

    total_cost = int(order_quantity) * baseInventory[item_name].per_item_cost
    order = OrderPayload(item_name=item_name, quantity=int(order_quantity), total_cost=total_cost)
    print(f'Starting order workflow, purchasing {order_quantity} of {item_name}', flush=True)
    start_resp = daprClient.start_workflow(workflow_component=workflow_component,
                                            workflow_name=workflow_name,
                                            input=order)
    _id = start_resp.instance_id

    def prompt_for_approval(daprClient: DaprClient):
        daprClient.raise_workflow_event(instance_id=_id, workflow_component=workflow_component, 
                                        event_name="manager_approval", event_data={'approval': True})

    approval_seeked = False
    start_time = datetime.now()
    while True:
        time_delta = datetime.now() - start_time
        state = daprClient.get_workflow(instance_id=_id, workflow_component=workflow_component)
        if not state:
            print("Workflow not found!")  # not expected
        elif state.runtime_status == "Completed" or\
                state.runtime_status == "Failed" or\
                state.runtime_status == "Terminated":
            print(f'Workflow completed! Result: {state.runtime_status}', flush=True)
            break
        if time_delta.total_seconds() >= 10:
            state = daprClient.get_workflow(instance_id=_id, workflow_component=workflow_component)
            if total_cost > 50000 and (
                state.runtime_status != "Completed" or 
                state.runtime_status != "Failed" or
                state.runtime_status != "Terminated"
                ) and not approval_seeked:
                approval_seeked = True
                threading.Thread(target=prompt_for_approval(daprClient), daemon=True).start()
        
    print("Purchase of item is ", state.runtime_status, flush=True)

def restock_inventory(self, daprClient: DaprClient, baseInventory):
    for key, item in baseInventory.items():
        print(f'item: {item}')
        item_str = f'{{"name": "{item.item_name}", "quantity": {item.quantity},\
                        "per_item_cost": {item.per_item_cost}}}'
        daprClient.save_state(store_name, key, item_str)
export const orderProcessingWorkflow: TWorkflow = async function* (ctx: WorkflowContext, orderPayLoad: OrderPayload): any {
  const orderId = ctx.getWorkflowInstanceId();
  console.log(`Processing order ${orderId}...`);

  const orderNotification: OrderNotification = {
    message: `Received order ${orderId} for ${orderPayLoad.quantity} ${orderPayLoad.itemName} at a total cost of ${orderPayLoad.totalCost}`,
  };
  yield ctx.callActivity(notifyActivity, orderNotification);

  const inventoryRequest = new InventoryRequest(orderId, orderPayLoad.itemName, orderPayLoad.quantity);
  const inventoryResult = yield ctx.callActivity(reserveInventoryActivity, inventoryRequest);

  if (!inventoryResult.success) {
    const orderNotification: OrderNotification = {
      message: `Insufficient inventory for order ${orderId}`,
    };
    yield ctx.callActivity(notifyActivity, orderNotification);
    return;
  }

  if (orderPayLoad.totalCost > 5000) {
    const approvalResult = yield ctx.callActivity(requestApprovalActivity, orderPayLoad);
    if (!approvalResult) {
      const orderNotification: OrderNotification = {
        message: `Order ${orderId} approval denied`,
      };
      yield ctx.callActivity(notifyActivity, orderNotification);
      return;
    }
  }

  const orderPaymentRequest = new OrderPaymentRequest(orderId, orderPayLoad.itemName, orderPayLoad.totalCost, orderPayLoad.quantity);
  const paymentResult = yield ctx.callActivity(processPaymentActivity, orderPaymentRequest);

  if (!paymentResult) {
    const orderNotification: OrderNotification = {
      message: `Payment for order ${orderId} failed`,
    };
    yield ctx.callActivity(notifyActivity, orderNotification);
    return;
  }

  const updatedResult = yield ctx.callActivity(updateInventoryActivity, inventoryRequest);
  if (!updatedResult.success) {
    const orderNotification: OrderNotification = {
      message: `Failed to update inventory for order ${orderId}`,
    };
    yield ctx.callActivity(notifyActivity, orderNotification);
    return;
  }

  const orderCompletedNotification: OrderNotification = {
    message: `order ${orderId} processed successfully!`,
  };
  yield ctx.callActivity(notifyActivity, orderCompletedNotification);

  console.log(`Order ${orderId} processed successfully!`);
}
public WorkflowStub create() {
    return ctx -> {
      Logger logger = ctx.getLogger();
      String orderId = ctx.getInstanceId();
      logger.info("Starting Workflow: " + ctx.getName());
      logger.info("Instance ID(order ID): " + orderId);
      logger.info("Current Orchestration Time: " + ctx.getCurrentInstant());

      OrderPayload order = ctx.getInput(OrderPayload.class);
      logger.info("Received Order: " + order.toString());
      OrderResult orderResult = new OrderResult();
      orderResult.setProcessed(false);

      // Notify the user that an order has come through
      Notification notification = new Notification();
      notification.setMessage("Received Order: " + order.toString());
      ctx.callActivity(NotifyActivity.class.getName(), notification).await();

      // Determine if there is enough of the item available for purchase by checking
      // the inventory
      InventoryRequest inventoryRequest = new InventoryRequest();
      inventoryRequest.setRequestId(orderId);
      inventoryRequest.setItemName(order.getItemName());
      inventoryRequest.setQuantity(order.getQuantity());
      InventoryResult inventoryResult = ctx.callActivity(ReserveInventoryActivity.class.getName(),
          inventoryRequest, InventoryResult.class).await();

      // If there is insufficient inventory, fail and let the user know
      if (!inventoryResult.isSuccess()) {
        notification.setMessage("Insufficient inventory for order : " + order.getItemName());
        ctx.callActivity(NotifyActivity.class.getName(), notification).await();
        ctx.complete(orderResult);
        return;
      }

      // Require orders over a certain threshold to be approved
      if (order.getTotalCost() > 5000) {
        ApprovalResult approvalResult = ctx.callActivity(RequestApprovalActivity.class.getName(),
            order, ApprovalResult.class).await();
        if (approvalResult != ApprovalResult.Approved) {
          notification.setMessage("Order " + order.getItemName() + " was not approved.");
          ctx.callActivity(NotifyActivity.class.getName(), notification).await();
          ctx.complete(orderResult);
          return;
        }
      }

      // There is enough inventory available so the user can purchase the item(s).
      // Process their payment
      PaymentRequest paymentRequest = new PaymentRequest();
      paymentRequest.setRequestId(orderId);
      paymentRequest.setItemBeingPurchased(order.getItemName());
      paymentRequest.setQuantity(order.getQuantity());
      paymentRequest.setAmount(order.getTotalCost());
      boolean isOK = ctx.callActivity(ProcessPaymentActivity.class.getName(),
          paymentRequest, boolean.class).await();
      if (!isOK) {
        notification.setMessage("Payment failed for order : " + orderId);
        ctx.callActivity(NotifyActivity.class.getName(), notification).await();
        ctx.complete(orderResult);
        return;
      }

      inventoryResult = ctx.callActivity(UpdateInventoryActivity.class.getName(),
          inventoryRequest, InventoryResult.class).await();
      if (!inventoryResult.isSuccess()) {
        
        notification.setMessage("Order failed to update inventory! : " + orderId);
        ctx.callActivity(NotifyActivity.class.getName(), notification).await();
        ctx.complete(orderResult);
        return;
      }

      // Let user know their order was processed
      notification.setMessage("Order completed! : " + orderId);
      ctx.callActivity(NotifyActivity.class.getName(), notification).await();

      // Complete the workflow with order result is processed
      orderResult.setProcessed(true);
      ctx.complete(orderResult);
    };
}
func OrderProcessingWorkflow(ctx *workflow.WorkflowContext) (any, error) {
    orderID := ctx.InstanceID()
    var orderPayload OrderPayload
    if err := ctx.GetInput(&orderPayload); err != nil {
        return nil, err
    }
    err := ctx.CallActivity(NotifyActivity, workflow.ActivityInput(Notification{
        Message: fmt.Sprintf("Received order %s for %d %s - $%d", orderID, orderPayload.Quantity, orderPayload.ItemName, orderPayload.TotalCost),
    })).Await(nil)
    if err != nil {
        return OrderResult{Processed: false}, err
    }

    var verifyInventoryResult InventoryResult
    if err := ctx.CallActivity(VerifyInventoryActivity, workflow.ActivityInput(InventoryRequest{
        RequestID: orderID,
        ItemName:  orderPayload.ItemName,
        Quantity:  orderPayload.Quantity,
    })).Await(&verifyInventoryResult); err != nil {
            return OrderResult{Processed: false}, err
    }

    if !verifyInventoryResult.Success {
        notification := Notification{Message: fmt.Sprintf("Insufficient inventory for %s", orderPayload.ItemName)}
        err := ctx.CallActivity(NotifyActivity, workflow.ActivityInput(notification)).Await(nil)
        return OrderResult{Processed: false}, err
    }

    if orderPayload.TotalCost > 50000 {
        var approvalRequired ApprovalRequired
        if err := ctx.CallActivity(RequestApprovalActivity, workflow.ActivityInput(orderPayload)).Await(&approvalRequired); err != nil {
                return OrderResult{Processed: false}, err
        }
        if err := ctx.WaitForExternalEvent("manager_approval", time.Second*200).Await(nil); err != nil {
                return OrderResult{Processed: false}, err
        }
        // TODO: Confirm timeout flow - this will be in the form of an error.
        if approvalRequired.Approval {
                if err := ctx.CallActivity(NotifyActivity, workflow.ActivityInput(Notification{Message: fmt.Sprintf("Payment for order %s has been approved!", orderID)})).Await(nil); err != nil {
                        log.Printf("failed to notify of a successful order: %v\n", err)
                }
        } else {
                if err := ctx.CallActivity(NotifyActivity, workflow.ActivityInput(Notification{Message: fmt.Sprintf("Payment for order %s has been rejected!", orderID)})).Await(nil); err != nil {
                        log.Printf("failed to notify of an unsuccessful order :%v\n", err)
                }
                return OrderResult{Processed: false}, err
        }
    }
    err = ctx.CallActivity(ProcessPaymentActivity, workflow.ActivityInput(PaymentRequest{
        RequestID:          orderID,
        ItemBeingPurchased: orderPayload.ItemName,
        Amount:             orderPayload.TotalCost,
        Quantity:           orderPayload.Quantity,
    })).Await(nil)
    if err != nil {
        if err := ctx.CallActivity(NotifyActivity, workflow.ActivityInput(Notification{Message: fmt.Sprintf("Order %s failed!", orderID)})).Await(nil); err != nil {
                log.Printf("failed to notify of a failed order: %v", err)
        }
        return OrderResult{Processed: false}, err
    }

    err = ctx.CallActivity(UpdateInventoryActivity, workflow.ActivityInput(PaymentRequest{
        RequestID:          orderID,
        ItemBeingPurchased: orderPayload.ItemName,
        Amount:             orderPayload.TotalCost,
        Quantity:           orderPayload.Quantity,
    })).Await(nil)
    if err != nil {
        if err := ctx.CallActivity(NotifyActivity, workflow.ActivityInput(Notification{Message: fmt.Sprintf("Order %s failed!", orderID)})).Await(nil); err != nil {
                log.Printf("failed to notify of a failed order: %v", err)
        }
        return OrderResult{Processed: false}, err
    }

    if err := ctx.CallActivity(NotifyActivity, workflow.ActivityInput(Notification{Message: fmt.Sprintf("Order %s has completed!", orderID)})).Await(nil); err != nil {
        log.Printf("failed to notify of a successful order: %v", err)
    }
    return OrderResult{Processed: true}, err
}

Create event-driven apps that scale to millions of events/sec. Integrates with dozens of message brokers.

  • Configurable push/pull eventing

  • At-least-once guaranteed message delivery

  • Automatic CloudEvents support

  • Bulk message delivery

publish message
using Dapr.Client;

var client = new DaprClientBuilder().Build();

// Publish message
await client.PublishEventAsync(“my-pubsub”, "my-topic", 
                               “my-message”);
from dapr.clients import DaprClient;

with DaprClient() as d:
  result = d.publish_event(
    pubsub_name = "my-pubsub",
    topic_name = 'orders',
    data = `{ "orderId": 1 }`,
    data_content_type = 'application/json')
import { DaprClient } from "@dapr/dapr";

(async () => {
  const client = new DaprClient();
  await client.pubsub.publish("my-pubsub", "orders", {"orderId":"1"});
})()
import io.dapr.client.DaprClient;
import io.dapr.client.DaprClientBuilder;
import io.dapr.client.domain.Metadata;

import static java.util.Collections.singletonMap;

DaprClient client = new DaprClientBuilder().build()
client.publishEvent("pubsub", "orders", "{\"orderId\":\"1\"}",
                    singletonMap(Metadata.TTL_IN_SECONDS, "600")).block();
package main

import (
        "context"
        "fmt"

        dapr "github.com/dapr/go-sdk/client"
)

func main() {
        client, err := dapr.NewClient()
        if err != nil {
                panic(fmt.Errorf("error creating connection to catalyst: %w", err))
        }
        defer client.Close()

        if err := client.PublishEvent(context.TODO(), "pubsub", "{topic-name}",
                []byte(`{"key":"value"}`)); err != nil {
                panic(fmt.Errorf("error publishing event: %w", err))
        }
}

Connect apps running on any cloud platform and across any region.

  • Zero networking configuration

  • Service discovery

  • End-to-end mTLS & authorization

connect app
using Dapr.Client;

var client = new DaprClientBuilder().Build();
var httpClient = DaprClient.CreateInvokeHttpClient(“order-processor”);
httpClient.DefaultRequestHeaders.Add("dapr-api-token", “my-api-token”);

var response = await httpClient.PostAsync("/orders", "{\"data\":\"my-data\"}");
headers = { 'dapr-app-id': ‘orderprocessor’, 'content-type': 'application/json'}

result = requests.post(
  url = '/orders',
  data =‘{\"data\":\"my-data\"}’, headers = headers)
import axios from "axios";

(async () => {
  let axiosConfig = {
    headers: {
        "dapr-app-id": "order-processor"
    }
  };

  const order = { orderId: 1 };
  const res = await axios.post(`/orders`, order , axiosConfig);
})()
private static final HttpClient httpClient = HttpClient.newBuilder()
        .version(HttpClient.Version.HTTP_2)
        .connectTimeout(Duration.ofSeconds(10))
        .build();

public static void main(String[] args) throws InterruptedException, IOException {
        int orderId = 1;
        JSONObject obj = new JSONObject();
        obj.put("orderId", orderId);

        HttpRequest request = HttpRequest.newBuilder()
                .POST(HttpRequest.BodyPublishers.ofString(obj.toString()))
                .uri(URI.create(dapr_url))
                .header("Content-Type", "application/json")
                .header("dapr-app-id", "order-processor")
                .build();

        HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
        System.out.println("Order passed: "+ orderId);
}
package main

import (
	"context"
	"fmt"
	"net/http"

	dapr "github.com/dapr/go-sdk/client"
)

func main() {
	client, err := dapr.NewClient()
	if err != nil {
		panic(err)
	}
	defer client.Close()

	order := `{"orderId":` + strconv.Itoa(i) + "}"
	req, err := http.NewRequest("POST", "/orders", strings.NewReader(order))
	if err != nil {
		panic()
	}
	req.Header.Add("dapr-app-id", "order-processor")

	response, err := client.Do(req)
	if err != nil {
		panic()
    }
}

Create CRUD applications with key/value state. Integrates with dozens of databases.

  • Data isolation for multi-tenancy

  • Configurable concurrency (first-write-wins, last-write-wins)

  • Configurable consistency (strong,  eventual)

  • Caching support with TTL

connect database
using Dapr.Client;

var client = new DaprClientBuilder().Build();
await client.SaveStateAsync(“my-database”, “1”, “myvalue”);
from dapr.clients import DaprClient

with DaprClient() as d:
    order = {'orderId': "1", "name": "lightsaber (real)"}
    client.save_state("my-database", "1", str(order))
import { DaprClient } from "@dapr/dapr"

const order = { orderId: "1" }
const state = [
    {
        key: order.orderId,
        value: order,
        options: {
            consistency: "strong",
            concurrency: "first-write-wins"
        }
    }
]

const client = new DaprClient();
await client.state.save("my-database", state)
import io.dapr.client.DaprClient;
import io.dapr.client.DaprClientBuilder;

DaprClient client = new DaprClientBuilder().build();
               
Order order = new Order();
order.setOrderId(orderId);

client.saveState("my-database", String.valueOf(orderId), order).block();
package main

import (
        "context"
        "fmt"

        dapr "github.com/dapr/go-sdk/client"
)

func main() {
        client, err := dapr.NewClient()
        if err != nil {
                panic()
        }
        defer client.Close()

        if err := err := client.SaveState(context.Background(), 
                         "my-database, "order", []byte("value), nil); err != nil {
                panic()
        }
}

Interact with external systems via triggers and outgoing calls.

  • Integrations with dozens of third party services

  • Authenticate calls to/from external systems

Connect System
using Dapr.Client;

var client = new DaprClientBuilder().Build();
await client.InvokeBindingAsync(“my-binding”, “create”, “my-data”);
from dapr.clients import DaprClient

with DaprClient() as d:
    resp = d.invoke_binding(
      binding_name="my-binding", 
      operation="create", data="100")
import { DaprClient } from "@dapr/dapr";

(async () => {
  const client = new DaprClient();
  await client.binding.send("my-binding", "create", 100);
})()
import io.dapr.client.DaprClient;
import io.dapr.client.DaprClientBuilder;

DaprClient client = new DaprClientBuilder().build()
client.invokeBinding("my-binding", "create", "100").block();
package main

import (
        "context"
        "fmt"

        dapr "github.com/dapr/go-sdk/client"
)

func main() {
        client, err := dapr.NewClient()
        if err != nil {
                panic(fmt.Errorf("error creating connection to catalyst: %w", err))
        }
        defer client.Close()

        err = client.InvokeOutputBinding(context.TODO(),
                &dapr.InvokeBindingRequest{
                        Name:      "my-binding",
                        Operation: "create",
                        Data:      []byte(`100`),
                })
        if err != nil {
                panic(err)
        }
}

decouple your apps from infrastructure

Dapr's component model decouples your code from your infrastructure giving you cloud & edge portability. For example with the pub/sub API you can change the message broker by swapping out a component file from RabbitMQ to Kafka or any other supported broker without changing your code.

Get started

built-in

end-to-end security

Secure the calls between your applications along with secure messaging on any message broker

access control

Specify which applications can access what infrastructure dependency and apply advanced access control and RBAC for your applications

multi-tenancy

Apply data isolation to your apps, preventing cross-lateral attacks and data breaches

retries

Choose between constant and exponential retries and apply them to service to service calls as well as any interaction with your underlying infrastructure

circuit breakers

Protect against outages by applying gated circuit breakers to allow your infrastructure to heal on its own

timeouts

Easily terminate long running operations by applying timeouts to service to service calls and any interaction with your underlying infrastructure

metrics

Get deep insights to request latency, throughput, error rates, and resource utilization (CPU, memory)

tracing

Automatic tracing makes it easy to understand the end-to-end flow of requests across your applications. See real-time visualizations across code and infrastructure. with no code instrumentation.

audit logs

Detailed trail of activities on your applications providing accountability, compliance with regulations and security monitoring.

join the tens of thousands of developers using dapr to easily build microservices

More Case Studies

30%

Typical developer time savings
Read the report
using the dapr SDK to publish events, we could focus on what we wanted to do - the real things that matter - not how to implement them.
Jasper Meng

Lead Developer, RioT working for BOSCH

See More

dapr really simplifies the case of distributed application architectures. with dapr, any developer can do it.
Kai Walter

Lead Architect, Carl ZEISS Vision Int. GmbH

See More

by adopting dapr, our customers can build portable and robust distributed systems faster.
Li Xiang

Software Engineer, Alibaba Cloud

See More

choose your path

community
Open-Source community Dapr.
Run and operate yourself
dapr on kubernetes
Enterprise Dapr for Kubernetes with dedicated support & CVE resolution
fully managed dapr
Dapr as a service.
Access the Dapr APIs from anywhere

building on
open source dapr

Dapr provides developers with APIs that abstract away the complexity of common challenges when building distributed applications. By letting Dapr take care of the complex challenges such as service communication, pub/sub, state management, workflow and secret management, developers can focus on business value and keep code lean and portable.

Diagrid’s founders were also the creators of the open source Dapr project. Along with the rest of the Diagrid team, they continue to play an active part in leading and contributing to the project.

24k

github stars

github

7.7k

discord members

Discord

3.6k

contributors

contributors