Client

Dapr client允许您的 Go 应用程序与其他 Dapr 应用程序进行交互。

前期准备

导入客户端包

  1. import "github.com/dapr/go-sdk/client"

错误处理

Dapr错误基于gRPC更丰富的错误模型。 以下代码显示了一个示例,展示了如何解析和处理错误详情:

  1. if err != nil {
  2. st := status.Convert(err)
  3. fmt.Printf("Code: %s\n", st.Code().String())
  4. fmt.Printf("Message: %s\n", st.Message())
  5. for _, detail := range st.Details() {
  6. switch t := detail.(type) {
  7. case *errdetails.ErrorInfo:
  8. // Handle ErrorInfo details
  9. fmt.Printf("ErrorInfo:\n- Domain: %s\n- Reason: %s\n- Metadata: %v\n", t.GetDomain(), t.GetReason(), t.GetMetadata())
  10. case *errdetails.BadRequest:
  11. // Handle BadRequest details
  12. fmt.Println("BadRequest:")
  13. for _, violation := range t.GetFieldViolations() {
  14. fmt.Printf("- Key: %s\n", violation.GetField())
  15. fmt.Printf("- The %q field was wrong: %s\n", violation.GetField(), violation.GetDescription())
  16. }
  17. case *errdetails.ResourceInfo:
  18. // Handle ResourceInfo details
  19. fmt.Printf("ResourceInfo:\n- Resource type: %s\n- Resource name: %s\n- Owner: %s\n- Description: %s\n",
  20. t.GetResourceType(), t.GetResourceName(), t.GetOwner(), t.GetDescription())
  21. case *errdetails.Help:
  22. // Handle ResourceInfo details
  23. fmt.Println("HelpInfo:")
  24. for _, link := range t.GetLinks() {
  25. fmt.Printf("- Url: %s\n", link.Url)
  26. fmt.Printf("- Description: %s\n", link.Description)
  27. }
  28. default:
  29. // Add cases for other types of details you expect
  30. fmt.Printf("Unhandled error detail type: %v\n", t)
  31. }
  32. }
  33. }

构建块

Go SDK 允许您与所有的Dapr构建块}进行接口交互。

服务调用

要在 Dapr sidecar 运行的服务上调用特定方法,Dapr 客户端 Go SDK 提供了两个选项:

调用没有数据的服务:

  1. resp, err := client.InvokeMethod(ctx, "app-id", "method-name", "post")

调用有数据的服务:

  1. content := &dapr.DataContent{
  2. ContentType: "application/json",
  3. Data: []byte(`{ "id": "a123", "value": "demo", "valid": true }`),
  4. }
  5. resp, err = client.InvokeMethodWithContent(ctx, "app-id", "method-name", "post", content)

有关服务调用的完整指南,请访问操作方法: 调用服务

状态管理

对于简单的用例,Dapr客户端提供了易于使用的SaveGetDelete方法:

  1. ctx := context.Background()
  2. data := []byte("hello")
  3. store := "my-store" // defined in the component YAML
  4. // save state with the key key1, default options: strong, last-write
  5. if err := client.SaveState(ctx, store, "key1", data, nil); err != nil {
  6. panic(err)
  7. }
  8. // get state for key key1
  9. item, err := client.GetState(ctx, store, "key1", nil)
  10. if err != nil {
  11. panic(err)
  12. }
  13. fmt.Printf("data [key:%s etag:%s]: %s", item.Key, item.Etag, string(item.Value))
  14. // delete state for key key1
  15. if err := client.DeleteState(ctx, store, "key1", nil); err != nil {
  16. panic(err)
  17. }

为了获得更精细的控制,Dapr Go客户端公开了SetStateItem类型,可以用于对状态操作进行更多控制,并允许一次保存多个项目:

  1. item1 := &dapr.SetStateItem{
  2. Key: "key1",
  3. Etag: &ETag{
  4. Value: "1",
  5. },
  6. Metadata: map[string]string{
  7. "created-on": time.Now().UTC().String(),
  8. },
  9. Value: []byte("hello"),
  10. Options: &dapr.StateOptions{
  11. Concurrency: dapr.StateConcurrencyLastWrite,
  12. Consistency: dapr.StateConsistencyStrong,
  13. },
  14. }
  15. item2 := &dapr.SetStateItem{
  16. Key: "key2",
  17. Metadata: map[string]string{
  18. "created-on": time.Now().UTC().String(),
  19. },
  20. Value: []byte("hello again"),
  21. }
  22. item3 := &dapr.SetStateItem{
  23. Key: "key3",
  24. Etag: &dapr.ETag{
  25. Value: "1",
  26. },
  27. Value: []byte("hello again"),
  28. }
  29. if err := client.SaveBulkState(ctx, store, item1, item2, item3); err != nil {
  30. panic(err)
  31. }

同样,GetBulkState方法提供了一种在单个操作中检索多个状态项的方式:

  1. keys := []string{"key1", "key2", "key3"}
  2. items, err := client.GetBulkState(ctx, store, keys, nil,100)

还有 ExecuteStateTransaction 可以事务性地执行多个upsert或delete操作。

  1. ops := make([]*dapr.StateOperation, 0)
  2. op1 := &dapr.StateOperation{
  3. Type: dapr.StateOperationTypeUpsert,
  4. Item: &dapr.SetStateItem{
  5. Key: "key1",
  6. Value: []byte(data),
  7. },
  8. }
  9. op2 := &dapr.StateOperation{
  10. Type: dapr.StateOperationTypeDelete,
  11. Item: &dapr.SetStateItem{
  12. Key: "key2",
  13. },
  14. }
  15. ops = append(ops, op1, op2)
  16. meta := map[string]string{}
  17. err := testClient.ExecuteStateTransaction(ctx, store, meta, ops)

使用QueryState从您的状态存储中检索、过滤和排序键/值数据。

  1. // Define the query string
  2. query := `{
  3. "filter": {
  4. "EQ": { "value.Id": "1" }
  5. },
  6. "sort": [
  7. {
  8. "key": "value.Balance",
  9. "order": "DESC"
  10. }
  11. ]
  12. }`
  13. // Use the client to query the state
  14. queryResponse, err := c.QueryState(ctx, "querystore", query)
  15. if err != nil {
  16. log.Fatal(err)
  17. }
  18. fmt.Printf("Got %d\n", len(queryResponse))
  19. for _, account := range queryResponse {
  20. var data Account
  21. err := account.Unmarshal(&data)
  22. if err != nil {
  23. log.Fatal(err)
  24. }
  25. fmt.Printf("Account: %s has %f\n", data.ID, data.Balance)
  26. }

**注意:查询状态 API 目前处于 alpha 阶段

有关状态管理的完整指南,请访问操作方法:保存和获取状态

发布消息

要将数据发布到主题上,Dapr Go 客户端提供了一个简单的方法:

  1. data := []byte(`{ "id": "a123", "value": "abcdefg", "valid": true }`)
  2. if err := client.PublishEvent(ctx, "component-name", "topic-name", data); err != nil {
  3. panic(err)
  4. }

要一次发布多条消息,PublishEvents 可以使用的方法:

  1. events := []string{"event1", "event2", "event3"}
  2. res := client.PublishEvents(ctx, "component-name", "topic-name", events)
  3. if res.Error != nil {
  4. panic(res.Error)
  5. }

有关pub/sub的完整指南,请访问操作方法: 发布 & 订阅

输出绑定

Dapr Go Client SDK 提供了两种方法来调用 Dapr 定义好的绑定操作方法。 Dapr 支持输入、输出和双向绑定。

比如,输出绑定:

  1. in := &dapr.InvokeBindingRequest{ Name: "binding-name", Operation: "operation-name" }
  2. err = client.InvokeOutputBinding(ctx, in)

调用带有内容和元数据的方法。

  1. in := &dapr.InvokeBindingRequest{
  2. Name: "binding-name",
  3. Operation: "operation-name",
  4. Data: []byte("hello"),
  5. Metadata: map[string]string{"k1": "v1", "k2": "v2"},
  6. }
  7. out, err := client.InvokeBinding(ctx, in)

有关输出绑定的完整指南,请访问操作方法:使用绑定

Actors

使用Dapr Go客户端SDK编写actor。

  1. // MyActor represents an example actor type.
  2. type MyActor struct {
  3. actors.Actor
  4. }
  5. // MyActorMethod is a method that can be invoked on MyActor.
  6. func (a *MyActor) MyActorMethod(ctx context.Context, req *actors.Message) (string, error) {
  7. log.Printf("Received message: %s", req.Data)
  8. return "Hello from MyActor!", nil
  9. }
  10. func main() {
  11. // Create a Dapr client
  12. daprClient, err := client.NewClient()
  13. if err != nil {
  14. log.Fatal("Error creating Dapr client: ", err)
  15. }
  16. // Register the actor type with Dapr
  17. actors.RegisterActor(&MyActor{})
  18. // Create an actor client
  19. actorClient := actors.NewClient(daprClient)
  20. // Create an actor ID
  21. actorID := actors.NewActorID("myactor")
  22. // Get or create the actor
  23. err = actorClient.SaveActorState(context.Background(), "myactorstore", actorID, map[string]interface{}{"data": "initial state"})
  24. if err != nil {
  25. log.Fatal("Error saving actor state: ", err)
  26. }
  27. // Invoke a method on the actor
  28. resp, err := actorClient.InvokeActorMethod(context.Background(), "myactorstore", actorID, "MyActorMethod", &actors.Message{Data: []byte("Hello from client!")})
  29. if err != nil {
  30. log.Fatal("Error invoking actor method: ", err)
  31. }
  32. log.Printf("Response from actor: %s", resp.Data)
  33. // Wait for a few seconds before terminating
  34. time.Sleep(5 * time.Second)
  35. // Delete the actor
  36. err = actorClient.DeleteActor(context.Background(), "myactorstore", actorID)
  37. if err != nil {
  38. log.Fatal("Error deleting actor: ", err)
  39. }
  40. // Close the Dapr client
  41. daprClient.Close()
  42. }

有关 Actors 的完整指南,请访问Actors 构建块文档

密钥管理

Dapr client 还提供访问运行时的密钥,并可以由任何的密钥存储服务支持(例如: Kubernetes Secrets, HashiCorp Vault, or Azure KeyVault):

  1. opt := map[string]string{
  2. "version": "2",
  3. }
  4. secret, err := client.GetSecret(ctx, "store-name", "secret-name", opt)

鉴权

默认情况下,Dapr依靠网络边界限制对其API的访问。 然而,如果Dapr API 使用了基于令牌的身份验证配置,用户可以通过以下两种方式配置Go Dapr客户端鉴权:

环境变量

如果定义了 DAPR_API_TOKEN 环境变量,Dapr 将自动使用它来做 Dapr API 调用时的鉴权。

显式方法

此外,用户还可以在任何 Dapr client 实例上设置显式鉴权令牌。 该方法对多个 Dapr API 端点创建多个 client 的时候十分有用。

  1. func main() {
  2. client, err := dapr.NewClient()
  3. if err != nil {
  4. panic(err)
  5. }
  6. defer client.Close()
  7. client.WithAuthToken("your-Dapr-API-token-here")
  8. }

有关秘密的完整指南,请访问操作方法: 检索秘密

分布式锁

Dapr 客户端使用锁提供对资源的互斥访问。 使用锁,您可以:

  • 提供对数据库行、表或整个数据库的访问权限
  • 锁定从队列中按顺序读取信息
  1. package main
  2. import (
  3. "fmt"
  4. dapr "github.com/dapr/go-sdk/client"
  5. )
  6. func main() {
  7. client, err := dapr.NewClient()
  8. if err != nil {
  9. panic(err)
  10. }
  11. defer client.Close()
  12. resp, err := client.TryLockAlpha1(ctx, "lockstore", &dapr.LockRequest{
  13. LockOwner: "random_id_abc123",
  14. ResourceID: "my_file_name",
  15. ExpiryInSeconds: 60,
  16. })
  17. fmt.Println(resp.Success)
  18. }

有关分布式锁的完整指南,请访问操作方法:使用锁

Configuration

使用 Dapr 客户端 Go SDK,您可以使用以只读键/值对形式返回的配置项目,并订阅配置项目的更改。

获取配置

  1. items, err := client.GetConfigurationItem(ctx, "example-config", "mykey")
  2. if err != nil {
  3. panic(err)
  4. }
  5. fmt.Printf("get config = %s\n", (*items).Value)

配置订阅

  1. go func() {
  2. if err := client.SubscribeConfigurationItems(ctx, "example-config", []string{"mySubscribeKey1", "mySubscribeKey2", "mySubscribeKey3"}, func(id string, items map[string]*dapr.ConfigurationItem) {
  3. for k, v := range items {
  4. fmt.Printf("get updated config key = %s, value = %s \n", k, v.Value)
  5. }
  6. subscribeID = id
  7. }); err != nil {
  8. panic(err)
  9. }
  10. }()

有关配置的完整指南,请访问操作方法:从商店管理配置

Cryptography

使用 Dapr 客户端 Go SDK,您可以使用高级的 EncryptDecrypt 密码学 API 在处理数据流时进行文件的加密和解密。

加密

  1. // Encrypt the data using Dapr
  2. out, err := client.Encrypt(context.Background(), rf, dapr.EncryptOptions{
  3. // These are the 3 required parameters
  4. ComponentName: "mycryptocomponent",
  5. KeyName: "mykey",
  6. Algorithm: "RSA",
  7. })
  8. if err != nil {
  9. panic(err)
  10. }

加密

  1. // Decrypt the data using Dapr
  2. out, err := client.Decrypt(context.Background(), rf, dapr.EncryptOptions{
  3. // Only required option is the component name
  4. ComponentName: "mycryptocomponent",
  5. })

有关密码学的完整指南,请访问操作方法:使用密码学API

相关链接

Go SDK示例