mirror of https://github.com/dapr/go-sdk.git
comments, examples in readme, end readme for example
This commit is contained in:
parent
63d675f6d0
commit
7ca6c9c75c
182
Readme.md
182
Readme.md
|
@ -1,38 +1,174 @@
|
|||
# Dapr SDK for Go
|
||||
|
||||
This is the dapr SDK (client) for Go.
|
||||
|
||||
## Update the latest gRPC proto clients
|
||||
|
||||
```sh
|
||||
./protogen.sh
|
||||
```
|
||||
This is the dapr SDK (client) for go (golang). It covers all of the APIs described in Dapr's [protocol buffers](https://raw.githubusercontent.com/dapr/dapr/master/dapr/proto/) with focus on developer productivity.
|
||||
|
||||
## Installation
|
||||
|
||||
```
|
||||
go get github.com/dapr/go-sdk
|
||||
To install Dapr client package, you need to first [install go](https://golang.org/doc/install) and set up your development environment. To import Dapr go client in your code:
|
||||
|
||||
```go
|
||||
import "github.com/dapr/go-sdk/client"
|
||||
```
|
||||
|
||||
## Usage
|
||||
## Quick start
|
||||
|
||||
The `example` folder contains a Dapr enabled `serving` app a `client` app that uses this SDK to invoke Dapr API for state and events, `serving` app for service to service invocation, and a simple HTTP binding to illustrate output binding. To run the example:
|
||||
```go
|
||||
package main
|
||||
|
||||
1. Start the `serving` app in the `example/serving` directory
|
||||
import (
|
||||
dapr "github.com/dapr/go-sdk/client"
|
||||
)
|
||||
|
||||
```
|
||||
cd example/serving
|
||||
dapr run --app-id serving \
|
||||
--protocol grpc \
|
||||
--app-port 50001 \
|
||||
go run main.go
|
||||
func main() {
|
||||
client, err := dapr.NewClient()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
//TODO: use the client here
|
||||
}
|
||||
```
|
||||
|
||||
2. Start the `client` app in the `example/client` directory
|
||||
Assuming you have Dapr CLI installed locally, you can then launch your app like this:
|
||||
|
||||
```shell
|
||||
dapr run --app-id my-app --protocol grpc --app-port 50001 go run main.go
|
||||
```
|
||||
cd example/client
|
||||
dapr run --app-id caller \
|
||||
--components-path ./comp \
|
||||
go run main.go
|
||||
|
||||
See [example folder](./example) for complete example.
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
Few common Dapr client usage examples
|
||||
|
||||
### State
|
||||
|
||||
For simple use-cases, Dapr client provides easy to use methods:
|
||||
|
||||
```go
|
||||
ctx := context.Background()
|
||||
data := []byte("hello")
|
||||
store := "my-store" // defined in the component YAML
|
||||
|
||||
// save state with the key
|
||||
err = client.SaveStateData(ctx, store, "k1", "v1", data)
|
||||
handleErrors(err)
|
||||
|
||||
// get state for key
|
||||
out, etag, err := client.GetState(ctx, store, "k1")
|
||||
handleErrors(err)
|
||||
|
||||
// delete state for key
|
||||
err = client.DeleteState(ctx, store, "k1")
|
||||
handleErrors(err)
|
||||
```
|
||||
|
||||
The `StateItem` type exposed by Dapr client provides more granular control options:
|
||||
|
||||
```go
|
||||
data := &StateItem{
|
||||
Etag: "v1",
|
||||
Key: "k1",
|
||||
Metadata: map[string]string{
|
||||
"key1": "value1",
|
||||
"key2": "value2",
|
||||
},
|
||||
Value: []byte("hello"),
|
||||
Options: &StateOptions{
|
||||
Concurrency: StateConcurrencyLastWrite,
|
||||
Consistency: StateConsistencyStrong,
|
||||
RetryPolicy: &StateRetryPolicy{
|
||||
Threshold: 3,
|
||||
Pattern: RetryPatternExponential,
|
||||
Interval: time.Duration(5 * time.Second),
|
||||
},
|
||||
},
|
||||
}
|
||||
err = client.SaveStateItem(ctx, store, data)
|
||||
```
|
||||
|
||||
Similar `StateOptions` exist on `GetDate` and `DeleteState` methods. Additionally, Dapr client also provides a method to save multiple state items at once:
|
||||
|
||||
```go
|
||||
data := &State{
|
||||
StoreName: "my-store",
|
||||
States: []*StateItem{
|
||||
{
|
||||
Key: "k1",
|
||||
Value: []byte("message 1"),
|
||||
},
|
||||
{
|
||||
Key: "k2",
|
||||
Value: []byte("message 2"),
|
||||
},
|
||||
},
|
||||
}
|
||||
err = client.SaveState(ctx, data)
|
||||
```
|
||||
|
||||
### PubSub
|
||||
|
||||
To publish data onto a topic the Dapr client provides a simple method:
|
||||
|
||||
```go
|
||||
data := []byte("hello")
|
||||
err = client.PublishEvent(ctx, "topic-name", data)
|
||||
handleErrors(err)
|
||||
```
|
||||
|
||||
### Service Invocation
|
||||
|
||||
To invoke a specific method on another service running with Dapr sidecar, the Dapr client provides two options. To invoke a service without any data:
|
||||
|
||||
```go
|
||||
resp, err = client.InvokeService(ctx, "service-name", "method-name")
|
||||
handleErrors(err)
|
||||
```
|
||||
|
||||
And to invoke a service with data:
|
||||
|
||||
```go
|
||||
data := []byte("hello")
|
||||
resp, err := client.InvokeServiceWithContent(ctx, "service-name", "method-name", "text/plain", data)
|
||||
handleErrors(err)
|
||||
```
|
||||
|
||||
### Bindings
|
||||
|
||||
Similarly to Service, Dapr client provides two methods to invoke an operation on a [Dapr-defined binding](https://github.com/dapr/docs/tree/master/concepts/bindings). Dapr supports input, output, and bidirectional bindings so the first methods supports all of them along with metadata options:
|
||||
|
||||
```go
|
||||
data := []byte("hello")
|
||||
opt := map[string]string{
|
||||
"opt1": "value1",
|
||||
"opt2": "value2",
|
||||
}
|
||||
resp, meta, err := client.InvokeBinding(ctx, "binding-name", "operation-name", data, opt)
|
||||
handleErrors(err)
|
||||
```
|
||||
|
||||
And for simple, output only biding:
|
||||
|
||||
```go
|
||||
data := []byte("hello")
|
||||
err = client.InvokeOutputBinding(ctx, "binding-name", "operation-name", data)
|
||||
handleErrors(err)
|
||||
```
|
||||
|
||||
### Secrets
|
||||
|
||||
The Dapr client also provides access to the runtime secrets that can be backed by any number of secrete stores (e.g. Kubernetes Secrets, Hashicorp Vault, or Azure KeyVault):
|
||||
|
||||
```go
|
||||
opt := map[string]string{
|
||||
"version": "2",
|
||||
}
|
||||
secret, err = client.GetSecret(ctx, "store-name", "secret-name", opt)
|
||||
handleErrors(err)
|
||||
```
|
||||
|
||||
## Contributing to Dapr go client
|
||||
|
||||
See the [Contribution Guide](./CONTRIBUTING.md) to get started with building and developing.
|
|
@ -7,8 +7,8 @@ import (
|
|||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// InvokeBinding invokes specific operation on the configured Dapr binding
|
||||
// This method covers both the input, output, and bi-directional bindings
|
||||
// InvokeBinding invokes specific operation on the configured Dapr binding.
|
||||
// This method covers input, output, and bi-directional bindings.
|
||||
func (c *Client) InvokeBinding(ctx context.Context, name, op string, in []byte, min map[string]string) (out []byte, mout map[string]string, err error) {
|
||||
if name == "" {
|
||||
return nil, nil, errors.New("nil topic")
|
||||
|
@ -33,7 +33,8 @@ func (c *Client) InvokeBinding(ctx context.Context, name, op string, in []byte,
|
|||
return nil, nil, nil
|
||||
}
|
||||
|
||||
// InvokeOutputBinding invokes configured Dapr binding with data (allows nil)
|
||||
// InvokeOutputBinding invokes configured Dapr binding with data (allows nil).InvokeOutputBinding
|
||||
// This method differs from InvokeBinding in that it doesn't expect any content being returned from the invoked method.
|
||||
func (c *Client) InvokeOutputBinding(ctx context.Context, name, operation string, data []byte) error {
|
||||
_, _, err := c.InvokeBinding(ctx, name, operation, data, nil)
|
||||
if err != nil {
|
||||
|
|
|
@ -22,7 +22,7 @@ var (
|
|||
logger = log.New(os.Stdout, "", 0)
|
||||
)
|
||||
|
||||
// NewClient instantiates dapr client locally using port from DAPR_GRPC_PORT env var
|
||||
// NewClient instantiates Dapr client using DAPR_GRPC_PORT environment variable as port.
|
||||
func NewClient() (client *Client, err error) {
|
||||
port := os.Getenv(daprPortEnvVarName)
|
||||
if port == "" {
|
||||
|
@ -31,7 +31,7 @@ func NewClient() (client *Client, err error) {
|
|||
return NewClientWithPort(port)
|
||||
}
|
||||
|
||||
// NewClientWithPort instantiates dapr client locally for the specific port
|
||||
// NewClientWithPort instantiates Dapr using specific port.
|
||||
func NewClientWithPort(port string) (client *Client, err error) {
|
||||
if port == "" {
|
||||
return nil, errors.New("nil port")
|
||||
|
@ -39,7 +39,7 @@ func NewClientWithPort(port string) (client *Client, err error) {
|
|||
return NewClientWithAddress(net.JoinHostPort("127.0.0.1", port))
|
||||
}
|
||||
|
||||
// NewClientWithAddress instantiates dapr client configured for the specific address
|
||||
// NewClientWithAddress instantiates Dapr using specific address (inclding port).
|
||||
func NewClientWithAddress(address string) (client *Client, err error) {
|
||||
if address == "" {
|
||||
return nil, errors.New("nil address")
|
||||
|
@ -49,14 +49,10 @@ func NewClientWithAddress(address string) (client *Client, err error) {
|
|||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "error creating connection to '%s': %v", address, err)
|
||||
}
|
||||
client = &Client{
|
||||
connection: conn,
|
||||
protoClient: pb.NewDaprClient(conn),
|
||||
}
|
||||
return
|
||||
return NewClientWithConnection(conn), nil
|
||||
}
|
||||
|
||||
// NewClientWithConnection instantiates dapr client configured for the specific connection
|
||||
// NewClientWithConnection instantiates Dapr client using specific connection.
|
||||
func NewClientWithConnection(conn *grpc.ClientConn) *Client {
|
||||
return &Client{
|
||||
connection: conn,
|
||||
|
@ -64,13 +60,13 @@ func NewClientWithConnection(conn *grpc.ClientConn) *Client {
|
|||
}
|
||||
}
|
||||
|
||||
// Client is the dapr client
|
||||
// Client is the Dapr client.
|
||||
type Client struct {
|
||||
connection *grpc.ClientConn
|
||||
protoClient pb.DaprClient
|
||||
}
|
||||
|
||||
// Close cleans up all resources created by the client
|
||||
// Close cleans up all resources created by the client.
|
||||
func (c *Client) Close() {
|
||||
if c.connection != nil {
|
||||
c.connection.Close()
|
||||
|
|
|
@ -29,7 +29,7 @@ func (c *Client) invokeServiceWithRequest(ctx context.Context, req *pb.InvokeSer
|
|||
return
|
||||
}
|
||||
|
||||
// InvokeService invokes service without data
|
||||
// InvokeService invokes service without raw data ([]byte).
|
||||
func (c *Client) InvokeService(ctx context.Context, serviceID, method string) (out []byte, err error) {
|
||||
if serviceID == "" {
|
||||
return nil, errors.New("nil serviceID")
|
||||
|
@ -46,7 +46,7 @@ func (c *Client) InvokeService(ctx context.Context, serviceID, method string) (o
|
|||
return c.invokeServiceWithRequest(ctx, req)
|
||||
}
|
||||
|
||||
// InvokeServiceWithContent invokes service without content
|
||||
// InvokeServiceWithContent invokes service without content (data + content type).
|
||||
func (c *Client) InvokeServiceWithContent(ctx context.Context, serviceID, method, contentType string, data []byte) (out []byte, err error) {
|
||||
if serviceID == "" {
|
||||
return nil, errors.New("nil serviceID")
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// PublishEvent is the message to publish event data to pubsub topic
|
||||
// PublishEvent pubishes data onto specific pubsub topic.
|
||||
func (c *Client) PublishEvent(ctx context.Context, topic string, in []byte) error {
|
||||
if topic == "" {
|
||||
return errors.New("nil topic")
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// GetSecret gets secret by key from specified store
|
||||
// GetSecret retreaves preconfigred secret from specified store using key.
|
||||
func (c *Client) GetSecret(ctx context.Context, store, key string, meta map[string]string) (out map[string]string, err error) {
|
||||
if store == "" {
|
||||
return nil, errors.New("nil store")
|
||||
|
|
|
@ -11,37 +11,38 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
// StateConsistencyUndefined is the undefined value for state consistency
|
||||
// StateConsistencyUndefined is the undefined value for state consistency.
|
||||
StateConsistencyUndefined StateConsistency = 0
|
||||
// StateConsistencyEventual represents eventual state consistency value
|
||||
// StateConsistencyEventual represents eventual state consistency value.
|
||||
StateConsistencyEventual StateConsistency = 1
|
||||
// StateConsistencyStrong represents strong state consistency value
|
||||
// StateConsistencyStrong represents strong state consistency value.
|
||||
StateConsistencyStrong StateConsistency = 2
|
||||
|
||||
// StateConcurrencyUndefined is the undefined value for state concurrency
|
||||
// StateConcurrencyUndefined is the undefined value for state concurrency.
|
||||
StateConcurrencyUndefined StateConcurrency = 0
|
||||
// StateConcurrencyFirstWrite represents first write concurrency value
|
||||
// StateConcurrencyFirstWrite represents first write concurrency value.
|
||||
StateConcurrencyFirstWrite StateConcurrency = 1
|
||||
// StateConcurrencyLastWrite represents last write concurrency value
|
||||
// StateConcurrencyLastWrite represents last write concurrency value.
|
||||
StateConcurrencyLastWrite StateConcurrency = 2
|
||||
|
||||
// RetryPatternUndefined is the undefined value for retry pattern
|
||||
// RetryPatternUndefined is the undefined value for retry pattern.
|
||||
RetryPatternUndefined RetryPattern = 0
|
||||
// RetryPatternLinear represents the linear retry pattern value
|
||||
// RetryPatternLinear represents the linear retry pattern value.
|
||||
RetryPatternLinear RetryPattern = 1
|
||||
// RetryPatternExponential represents the exponential retry pattern value
|
||||
// RetryPatternExponential represents the exponential retry pattern value.
|
||||
RetryPatternExponential RetryPattern = 2
|
||||
)
|
||||
|
||||
type (
|
||||
// StateConsistency is the consistency enum type
|
||||
// StateConsistency is the consistency enum type.
|
||||
StateConsistency int
|
||||
// StateConcurrency is the concurrency enum type
|
||||
// StateConcurrency is the concurrency enum type.
|
||||
StateConcurrency int
|
||||
// RetryPattern is the retry pattern enum type
|
||||
// RetryPattern is the retry pattern enum type.
|
||||
RetryPattern int
|
||||
)
|
||||
|
||||
// String returns the string value of the StateConsistency.
|
||||
func (c StateConsistency) String() string {
|
||||
names := [...]string{
|
||||
"Undefined",
|
||||
|
@ -55,8 +56,7 @@ func (c StateConsistency) String() string {
|
|||
return names[c]
|
||||
}
|
||||
|
||||
// End Consistency
|
||||
|
||||
// String returns the string value of the StateConcurrency.
|
||||
func (c StateConcurrency) String() string {
|
||||
names := [...]string{
|
||||
"Undefined",
|
||||
|
@ -70,7 +70,7 @@ func (c StateConcurrency) String() string {
|
|||
return names[c]
|
||||
}
|
||||
|
||||
// END Concurrency
|
||||
// String returns the string value of the RetryPattern.
|
||||
func (c RetryPattern) String() string {
|
||||
names := [...]string{
|
||||
"Undefined",
|
||||
|
@ -84,8 +84,6 @@ func (c RetryPattern) String() string {
|
|||
return names[c]
|
||||
}
|
||||
|
||||
// END Retry Pattern
|
||||
|
||||
var (
|
||||
stateOptionRetryPolicyDefault = &v1.StateRetryPolicy{
|
||||
Threshold: 3,
|
||||
|
@ -99,13 +97,13 @@ var (
|
|||
}
|
||||
)
|
||||
|
||||
// State is a collection of StateItems with a store name
|
||||
// State is a collection of StateItems with a store name.
|
||||
type State struct {
|
||||
StoreName string
|
||||
States []*StateItem
|
||||
}
|
||||
|
||||
// StateItem represents the state to be persisted
|
||||
// StateItem represents a single state to be persisted.
|
||||
type StateItem struct {
|
||||
Key string
|
||||
Value []byte
|
||||
|
@ -114,22 +112,20 @@ type StateItem struct {
|
|||
Options *StateOptions
|
||||
}
|
||||
|
||||
// StateOptions represents the state store persistence policy
|
||||
// StateOptions represents the state store persistence policy.
|
||||
type StateOptions struct {
|
||||
Concurrency StateConcurrency
|
||||
Consistency StateConsistency
|
||||
RetryPolicy *StateRetryPolicy
|
||||
}
|
||||
|
||||
// StateRetryPolicy represents the state store invocation retry policy
|
||||
// StateRetryPolicy represents the state store invocation retry policy.
|
||||
type StateRetryPolicy struct {
|
||||
Threshold int32
|
||||
Pattern RetryPattern
|
||||
Interval time.Duration
|
||||
}
|
||||
|
||||
// *** Converters
|
||||
|
||||
func toProtoSaveStateRequest(s *State) (req *pb.SaveStateRequest) {
|
||||
r := &pb.SaveStateRequest{
|
||||
StoreName: s.StoreName,
|
||||
|
@ -178,9 +174,7 @@ func toProtoDuration(d time.Duration) *duration.Duration {
|
|||
}
|
||||
}
|
||||
|
||||
// *** Save State ***
|
||||
|
||||
// SaveState saves the fully loaded save state request
|
||||
// SaveState saves the fully loaded state to store.
|
||||
func (c *Client) SaveState(ctx context.Context, s *State) error {
|
||||
if s == nil || s.StoreName == "" || s.States == nil || len(s.States) < 1 {
|
||||
return errors.New("nil or invalid state")
|
||||
|
@ -193,7 +187,7 @@ func (c *Client) SaveState(ctx context.Context, s *State) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// SaveStateItem saves a single state item
|
||||
// SaveStateItem saves the single state item to store.
|
||||
func (c *Client) SaveStateItem(ctx context.Context, store string, item *StateItem) error {
|
||||
if store == "" {
|
||||
return errors.New("nil store")
|
||||
|
@ -210,7 +204,7 @@ func (c *Client) SaveStateItem(ctx context.Context, store string, item *StateIte
|
|||
return c.SaveState(ctx, req)
|
||||
}
|
||||
|
||||
// SaveStateData saves the data into store using default state options
|
||||
// SaveStateData saves the raw data into store using default state options.
|
||||
func (c *Client) SaveStateData(ctx context.Context, store, key, etag string, data []byte) error {
|
||||
if store == "" {
|
||||
return errors.New("nil store")
|
||||
|
@ -233,9 +227,7 @@ func (c *Client) SaveStateData(ctx context.Context, store, key, etag string, dat
|
|||
return c.SaveState(ctx, req)
|
||||
}
|
||||
|
||||
// *** Get State ***
|
||||
|
||||
// GetStateWithConsistency retreaves state from specific store using provided request
|
||||
// GetStateWithConsistency retreaves state from specific store using provided state consistency.
|
||||
func (c *Client) GetStateWithConsistency(ctx context.Context, store, key string, sc StateConsistency) (out []byte, etag string, err error) {
|
||||
if store == "" {
|
||||
return nil, "", errors.New("nil store")
|
||||
|
@ -258,14 +250,12 @@ func (c *Client) GetStateWithConsistency(ctx context.Context, store, key string,
|
|||
return result.Data, result.Etag, nil
|
||||
}
|
||||
|
||||
// GetState retreaves state from specific store using default consistency option
|
||||
// GetState retreaves state from specific store using default consistency option.
|
||||
func (c *Client) GetState(ctx context.Context, store, key string) (out []byte, etag string, err error) {
|
||||
return c.GetStateWithConsistency(ctx, store, key, StateConsistencyStrong)
|
||||
}
|
||||
|
||||
// *** Delete State ***
|
||||
|
||||
// DeleteStateVersion deletes content from store using provided state options and etag
|
||||
// DeleteStateVersion deletes content from store using provided state options and etag.
|
||||
func (c *Client) DeleteStateVersion(ctx context.Context, store, key, etag string, opts *StateOptions) error {
|
||||
if store == "" {
|
||||
return errors.New("nil store")
|
||||
|
@ -289,7 +279,7 @@ func (c *Client) DeleteStateVersion(ctx context.Context, store, key, etag string
|
|||
return nil
|
||||
}
|
||||
|
||||
// DeleteState deletes content from store using default state options
|
||||
// DeleteState deletes content from store using default state options.
|
||||
func (c *Client) DeleteState(ctx context.Context, store, key string) error {
|
||||
return c.DeleteStateVersion(ctx, store, key, "", nil)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
# Dapr go client example
|
||||
|
||||
|
||||
The `example` folder contains a Dapr enabled `serving` app a `client` app that uses this SDK to invoke Dapr API for state and events, `serving` app for service to service invocation, and a simple HTTP binding to illustrate output binding. To run the example:
|
||||
|
||||
1. Start the `serving` app in the `example/serving` directory
|
||||
|
||||
```
|
||||
cd example/serving
|
||||
dapr run --app-id serving \
|
||||
--protocol grpc \
|
||||
--app-port 50001 \
|
||||
go run main.go
|
||||
```
|
||||
|
||||
2. Start the `client` app in the `example/client` directory
|
||||
|
||||
```
|
||||
cd example/client
|
||||
dapr run --app-id caller \
|
||||
--components-path ./comp \
|
||||
go run main.go
|
||||
```
|
Loading…
Reference in New Issue