mirror of https://github.com/dapr/go-sdk.git
request method verb on service invocation (#119)
* request method verb on service invocation * missing args tests * merge custom serialize * removes IDE specific stuff from project
This commit is contained in:
parent
bd7d126b4f
commit
ec13ce3483
|
@ -5,10 +5,10 @@ coverage:
|
||||||
default: false
|
default: false
|
||||||
client:
|
client:
|
||||||
paths: "client/"
|
paths: "client/"
|
||||||
threshold: 0% # don't allow coverage to drop on client
|
threshold: 2% # don't allow coverage to drop on client
|
||||||
service:
|
service:
|
||||||
paths: "service"
|
paths: "service"
|
||||||
threshold: 3% # allow coverage to drop on service by 3% (wip)
|
threshold: 2% # allow coverage to drop on service by 3% (wip)
|
||||||
ignore:
|
ignore:
|
||||||
- "dapr/proto/**"
|
- "dapr/proto/**"
|
||||||
- "example/**"
|
- "example/**"
|
||||||
|
|
|
@ -5,6 +5,9 @@
|
||||||
*.so
|
*.so
|
||||||
*.dylib
|
*.dylib
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.vscode
|
||||||
|
|
||||||
# Test binary, build with `go test -c`
|
# Test binary, build with `go test -c`
|
||||||
*.test
|
*.test
|
||||||
|
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
{
|
|
||||||
// Use IntelliSense to learn about possible attributes.
|
|
||||||
// Hover to view descriptions of existing attributes.
|
|
||||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
|
||||||
"version": "0.2.0",
|
|
||||||
"configurations": [
|
|
||||||
{
|
|
||||||
"name": "Launch",
|
|
||||||
"type": "go",
|
|
||||||
"request": "launch",
|
|
||||||
"mode": "auto",
|
|
||||||
"program": "${fileDirname}",
|
|
||||||
"env": {},
|
|
||||||
"args": []
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -40,13 +40,13 @@ type Client interface {
|
||||||
InvokeOutputBinding(ctx context.Context, in *BindingInvocation) error
|
InvokeOutputBinding(ctx context.Context, in *BindingInvocation) error
|
||||||
|
|
||||||
// InvokeService invokes service without raw data
|
// InvokeService invokes service without raw data
|
||||||
InvokeService(ctx context.Context, serviceID, method string) (out []byte, err error)
|
InvokeService(ctx context.Context, serviceID, method, verb string) (out []byte, err error)
|
||||||
|
|
||||||
// InvokeServiceWithContent invokes service with content
|
// InvokeServiceWithContent invokes service with content
|
||||||
InvokeServiceWithContent(ctx context.Context, serviceID, method string, content *DataContent) (out []byte, err error)
|
InvokeServiceWithContent(ctx context.Context, serviceID, method, verb string, content *DataContent) (out []byte, err error)
|
||||||
|
|
||||||
// InvokeServiceWithCustomContent invokes service with custom content (struct + content type).
|
// InvokeServiceWithCustomContent invokes service with custom content (struct + content type).
|
||||||
InvokeServiceWithCustomContent(ctx context.Context, serviceID, method string, contentType string, content interface{}) (out []byte, err error)
|
InvokeServiceWithCustomContent(ctx context.Context, serviceID, method, verb string, contentType string, content interface{}) (out []byte, err error)
|
||||||
|
|
||||||
// PublishEvent pubishes data onto topic in specific pubsub component.
|
// PublishEvent pubishes data onto topic in specific pubsub component.
|
||||||
PublishEvent(ctx context.Context, component, topic string, in []byte) error
|
PublishEvent(ctx context.Context, component, topic string, in []byte) error
|
||||||
|
|
|
@ -3,6 +3,7 @@ package client
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"strings"
|
||||||
|
|
||||||
v1 "github.com/dapr/go-sdk/dapr/proto/common/v1"
|
v1 "github.com/dapr/go-sdk/dapr/proto/common/v1"
|
||||||
pb "github.com/dapr/go-sdk/dapr/proto/runtime/v1"
|
pb "github.com/dapr/go-sdk/dapr/proto/runtime/v1"
|
||||||
|
@ -38,60 +39,65 @@ func (c *GRPCClient) invokeServiceWithRequest(ctx context.Context, req *pb.Invok
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// InvokeService invokes service without raw data ([]byte).
|
func verbToHTTPExtension(verb string) *v1.HTTPExtension {
|
||||||
func (c *GRPCClient) InvokeService(ctx context.Context, serviceID, method string) (out []byte, err error) {
|
if v, ok := v1.HTTPExtension_Verb_value[strings.ToUpper(verb)]; ok {
|
||||||
|
return &v1.HTTPExtension{Verb: v1.HTTPExtension_Verb(v)}
|
||||||
|
}
|
||||||
|
return &v1.HTTPExtension{Verb: v1.HTTPExtension_NONE}
|
||||||
|
}
|
||||||
|
|
||||||
|
func hasRequiredInvokeArgs(serviceID, method, verb string) error {
|
||||||
if serviceID == "" {
|
if serviceID == "" {
|
||||||
return nil, errors.New("nil serviceID")
|
return errors.New("serviceID")
|
||||||
}
|
}
|
||||||
if method == "" {
|
if method == "" {
|
||||||
return nil, errors.New("nil method")
|
return errors.New("method")
|
||||||
|
}
|
||||||
|
if verb == "" {
|
||||||
|
return errors.New("verb")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// InvokeService invokes service without raw data ([]byte).
|
||||||
|
func (c *GRPCClient) InvokeService(ctx context.Context, serviceID, method, verb string) (out []byte, err error) {
|
||||||
|
if err := hasRequiredInvokeArgs(serviceID, method, verb); err != nil {
|
||||||
|
return nil, errors.Wrap(err, "missing required parameter")
|
||||||
}
|
}
|
||||||
req := &pb.InvokeServiceRequest{
|
req := &pb.InvokeServiceRequest{
|
||||||
Id: serviceID,
|
Id: serviceID,
|
||||||
Message: &v1.InvokeRequest{
|
Message: &v1.InvokeRequest{
|
||||||
Method: method,
|
Method: method,
|
||||||
HttpExtension: &v1.HTTPExtension{
|
HttpExtension: verbToHTTPExtension(verb),
|
||||||
Verb: v1.HTTPExtension_POST,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
return c.invokeServiceWithRequest(ctx, req)
|
return c.invokeServiceWithRequest(ctx, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InvokeServiceWithContent invokes service without content (data + content type).
|
// InvokeServiceWithContent invokes service without content (data + content type).
|
||||||
func (c *GRPCClient) InvokeServiceWithContent(ctx context.Context, serviceID, method string, content *DataContent) (out []byte, err error) {
|
func (c *GRPCClient) InvokeServiceWithContent(ctx context.Context, serviceID, method, verb string, content *DataContent) (out []byte, err error) {
|
||||||
if serviceID == "" {
|
if err := hasRequiredInvokeArgs(serviceID, method, verb); err != nil {
|
||||||
return nil, errors.New("serviceID is required")
|
return nil, errors.Wrap(err, "missing required parameter")
|
||||||
}
|
|
||||||
if method == "" {
|
|
||||||
return nil, errors.New("method name is required")
|
|
||||||
}
|
}
|
||||||
if content == nil {
|
if content == nil {
|
||||||
return nil, errors.New("content required")
|
return nil, errors.New("content required")
|
||||||
}
|
}
|
||||||
|
|
||||||
req := &pb.InvokeServiceRequest{
|
req := &pb.InvokeServiceRequest{
|
||||||
Id: serviceID,
|
Id: serviceID,
|
||||||
Message: &v1.InvokeRequest{
|
Message: &v1.InvokeRequest{
|
||||||
Method: method,
|
Method: method,
|
||||||
Data: &anypb.Any{Value: content.Data},
|
Data: &anypb.Any{Value: content.Data},
|
||||||
ContentType: content.ContentType,
|
ContentType: content.ContentType,
|
||||||
HttpExtension: &v1.HTTPExtension{
|
HttpExtension: verbToHTTPExtension(verb),
|
||||||
Verb: v1.HTTPExtension_POST,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.invokeServiceWithRequest(ctx, req)
|
return c.invokeServiceWithRequest(ctx, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InvokeServiceWithCustomContent invokes service with custom content (struct + content type).
|
// InvokeServiceWithCustomContent invokes service with custom content (struct + content type).
|
||||||
func (c *GRPCClient) InvokeServiceWithCustomContent(ctx context.Context, serviceID, method string, contentType string, content interface{}) (out []byte, err error) {
|
func (c *GRPCClient) InvokeServiceWithCustomContent(ctx context.Context, serviceID, method, verb string, contentType string, content interface{}) (out []byte, err error) {
|
||||||
if serviceID == "" {
|
if err := hasRequiredInvokeArgs(serviceID, method, verb); err != nil {
|
||||||
return nil, errors.New("serviceID is required")
|
return nil, errors.Wrap(err, "missing required parameter")
|
||||||
}
|
|
||||||
if method == "" {
|
|
||||||
return nil, errors.New("method name is required")
|
|
||||||
}
|
}
|
||||||
if contentType == "" {
|
if contentType == "" {
|
||||||
return nil, errors.New("content type required")
|
return nil, errors.New("content type required")
|
||||||
|
@ -101,7 +107,6 @@ func (c *GRPCClient) InvokeServiceWithCustomContent(ctx context.Context, service
|
||||||
}
|
}
|
||||||
|
|
||||||
contentData, err := json.Marshal(content)
|
contentData, err := json.Marshal(content)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.WithMessage(err, "error serializing input struct")
|
return nil, errors.WithMessage(err, "error serializing input struct")
|
||||||
}
|
}
|
||||||
|
@ -109,12 +114,10 @@ func (c *GRPCClient) InvokeServiceWithCustomContent(ctx context.Context, service
|
||||||
req := &pb.InvokeServiceRequest{
|
req := &pb.InvokeServiceRequest{
|
||||||
Id: serviceID,
|
Id: serviceID,
|
||||||
Message: &v1.InvokeRequest{
|
Message: &v1.InvokeRequest{
|
||||||
Method: method,
|
Method: method,
|
||||||
Data: &anypb.Any{Value: contentData},
|
Data: &anypb.Any{Value: contentData},
|
||||||
ContentType: contentType,
|
ContentType: contentType,
|
||||||
HttpExtension: &v1.HTTPExtension{
|
HttpExtension: verbToHTTPExtension(verb),
|
||||||
Verb: v1.HTTPExtension_POST,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
v1 "github.com/dapr/go-sdk/dapr/proto/common/v1"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -22,7 +23,6 @@ type _testStructwithSlices struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// go test -timeout 30s ./client -count 1 -run ^TestInvokeServiceWithContent$
|
// go test -timeout 30s ./client -count 1 -run ^TestInvokeServiceWithContent$
|
||||||
|
|
||||||
func TestInvokeServiceWithContent(t *testing.T) {
|
func TestInvokeServiceWithContent(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
data := "ping"
|
data := "ping"
|
||||||
|
@ -32,7 +32,7 @@ func TestInvokeServiceWithContent(t *testing.T) {
|
||||||
ContentType: "text/plain",
|
ContentType: "text/plain",
|
||||||
Data: []byte(data),
|
Data: []byte(data),
|
||||||
}
|
}
|
||||||
resp, err := testClient.InvokeServiceWithContent(ctx, "test", "fn", content)
|
resp, err := testClient.InvokeServiceWithContent(ctx, "test", "fn", "post", content)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.NotNil(t, resp)
|
assert.NotNil(t, resp)
|
||||||
assert.Equal(t, string(resp), data)
|
assert.Equal(t, string(resp), data)
|
||||||
|
@ -40,18 +40,30 @@ func TestInvokeServiceWithContent(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("without content", func(t *testing.T) {
|
t.Run("without content", func(t *testing.T) {
|
||||||
resp, err := testClient.InvokeService(ctx, "test", "fn")
|
resp, err := testClient.InvokeService(ctx, "test", "fn", "get")
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Nil(t, resp)
|
assert.Nil(t, resp)
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("without service ID", func(t *testing.T) {
|
||||||
|
_, err := testClient.InvokeService(ctx, "", "fn", "get")
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
})
|
||||||
|
t.Run("without method", func(t *testing.T) {
|
||||||
|
_, err := testClient.InvokeService(ctx, "test", "", "get")
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
})
|
||||||
|
t.Run("without verb", func(t *testing.T) {
|
||||||
|
_, err := testClient.InvokeService(ctx, "test", "fn", "")
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
})
|
||||||
t.Run("from struct with text", func(t *testing.T) {
|
t.Run("from struct with text", func(t *testing.T) {
|
||||||
testdata := _testCustomContentwithText{
|
testdata := _testCustomContentwithText{
|
||||||
Key1: "value1",
|
Key1: "value1",
|
||||||
Key2: "value2",
|
Key2: "value2",
|
||||||
}
|
}
|
||||||
_, err := testClient.InvokeServiceWithCustomContent(ctx, "test", "fn", "text/plain", testdata)
|
_, err := testClient.InvokeServiceWithCustomContent(ctx, "test", "fn", "post", "text/plain", testdata)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -60,7 +72,7 @@ func TestInvokeServiceWithContent(t *testing.T) {
|
||||||
Key1: "value1",
|
Key1: "value1",
|
||||||
Key2: 2500,
|
Key2: 2500,
|
||||||
}
|
}
|
||||||
_, err := testClient.InvokeServiceWithCustomContent(ctx, "test", "fn", "text/plain", testdata)
|
_, err := testClient.InvokeServiceWithCustomContent(ctx, "test", "fn", "post", "text/plain", testdata)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -69,7 +81,27 @@ func TestInvokeServiceWithContent(t *testing.T) {
|
||||||
Key1: []string{"value1", "value2", "value3"},
|
Key1: []string{"value1", "value2", "value3"},
|
||||||
Key2: []int{25, 40, 600},
|
Key2: []int{25, 40, 600},
|
||||||
}
|
}
|
||||||
_, err := testClient.InvokeServiceWithCustomContent(ctx, "test", "fn", "text/plain", testdata)
|
_, err := testClient.InvokeServiceWithCustomContent(ctx, "test", "fn", "post", "text/plain", testdata)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestVerbParsing(t *testing.T) {
|
||||||
|
t.Run("valid lower case", func(t *testing.T) {
|
||||||
|
v := verbToHTTPExtension("post")
|
||||||
|
assert.NotNil(t, v)
|
||||||
|
assert.Equal(t, v1.HTTPExtension_POST, v.Verb)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("valid upper case", func(t *testing.T) {
|
||||||
|
v := verbToHTTPExtension("GET")
|
||||||
|
assert.NotNil(t, v)
|
||||||
|
assert.Equal(t, v1.HTTPExtension_GET, v.Verb)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("invalid verb", func(t *testing.T) {
|
||||||
|
v := verbToHTTPExtension("BAD")
|
||||||
|
assert.NotNil(t, v)
|
||||||
|
assert.Equal(t, v1.HTTPExtension_NONE, v.Verb)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -106,7 +106,7 @@ type StateItem struct {
|
||||||
Etag string
|
Etag string
|
||||||
}
|
}
|
||||||
|
|
||||||
// StateItem represents a single state item.
|
// BulkStateItem represents a single state item.
|
||||||
type BulkStateItem struct {
|
type BulkStateItem struct {
|
||||||
Key string
|
Key string
|
||||||
Value []byte
|
Value []byte
|
||||||
|
|
|
@ -71,7 +71,7 @@ func main() {
|
||||||
ContentType: "text/plain",
|
ContentType: "text/plain",
|
||||||
Data: []byte("hellow"),
|
Data: []byte("hellow"),
|
||||||
}
|
}
|
||||||
resp, err := client.InvokeServiceWithContent(ctx, "serving", "echo", content)
|
resp, err := client.InvokeServiceWithContent(ctx, "serving", "echo", "post", content)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue