Repository: goadesign/goa
Pull request #2369 (2019-11-06 10:04:16)

Generated client returns nil for streaming payload with no result
 When there is a streaming payload with no result, the generated transport-agnostic service client was returning nil instead of the client stream.

New test case "streaming-payload-no-result" would fail without this change.

raphael: Thank you! Can you please back port to v2 as well? thanks!

Patch:
diff --git a/codegen/service/client.go b/codegen/service/client.go
index 14babb02..cf732df6 100644
--- a/codegen/service/client.go
+++ b/codegen/service/client.go
@@ -79,18 +79,22 @@ const serviceClientMethodT = `
 	{{- end }}
 //	- error: internal error
 {{- end }}
-func (c *{{ .ClientVarName }}) {{ .VarName }}(ctx context.Context, {{ if .PayloadRef }}p {{ .PayloadRef }}{{ end }}) ({{ if .ClientStream }}res {{ .ClientStream.Interface }}, {{ else if .ResultRef }}res {{ .ResultRef }}, {{ end }}err error) {
-	{{- if .ResultRef }}
+{{- $resultType := .ResultRef }}
+{{- if .ClientStream }}
+	{{- $resultType = .ClientStream.Interface }}
+{{- end }}
+func (c *{{ .ClientVarName }}) {{ .VarName }}(ctx context.Context, {{ if .PayloadRef }}p {{ .PayloadRef }}{{ end }}) ({{ if $resultType }}res {{ $resultType }}, {{ end }}err error) {
+	{{- if $resultType }}
 	var ires interface{}
 	{{- end }}
-	{{ if .ResultRef }}ires{{ else }}_{{ end }}, err = c.{{ .VarName}}Endpoint(ctx, {{ if .PayloadRef }}p{{ else }}nil{{ end }})
-	{{- if not .ResultRef }}
+	{{ if $resultType }}ires{{ else }}_{{ end }}, err = c.{{ .VarName}}Endpoint(ctx, {{ if .PayloadRef }}p{{ else }}nil{{ end }})
+	{{- if not $resultType }}
 	return
 	{{- else }}
 	if err != nil {
 		return
 	}
-	return ires.({{ if .ClientStream }}{{ .ClientStream.Interface }}{{ else }}{{ .ResultRef }}{{ end }}), nil
+	return ires.({{ $resultType }}), nil
 	{{- end }}
 }
 `


Test patch:
diff --git a/codegen/service/client_test.go b/codegen/service/client_test.go
index d45009fa..ca83b3ad 100644
--- a/codegen/service/client_test.go
+++ b/codegen/service/client_test.go
@@ -18,12 +18,15 @@ func TestClient(t *testing.T) {
 		Code string
 	}{
 		{"single", testdata.SingleEndpointDSL, testdata.SingleMethodClient},
+		{"use", testdata.UseEndpointDSL, testdata.UseMethodClient},
 		{"multiple", testdata.MultipleEndpointsDSL, testdata.MultipleMethodsClient},
 		{"no-payload", testdata.NoPayloadEndpointDSL, testdata.NoPayloadMethodsClient},
+		{"with-result", testdata.WithResultEndpointDSL, testdata.WithResultMethodClient},
 		{"streaming-result", testdata.StreamingResultMethodDSL, testdata.StreamingResultMethodClient},
 		{"streaming-result-no-payload", testdata.StreamingResultNoPayloadMethodDSL, testdata.StreamingResultNoPayloadMethodClient},
 		{"streaming-payload", testdata.StreamingPayloadMethodDSL, testdata.StreamingPayloadMethodClient},
 		{"streaming-payload-no-payload", testdata.StreamingPayloadNoPayloadMethodDSL, testdata.StreamingPayloadNoPayloadMethodClient},
+		{"streaming-payload-no-result", testdata.StreamingPayloadNoResultMethodDSL, testdata.StreamingPayloadNoResultMethodClient},
 		{"bidirectional-streaming", testdata.BidirectionalStreamingMethodDSL, testdata.BidirectionalStreamingMethodClient},
 		{"bidirectional-streaming-no-payload", testdata.BidirectionalStreamingNoPayloadMethodDSL, testdata.BidirectionalStreamingNoPayloadMethodClient},
 	}
diff --git a/codegen/service/testdata/client_code.go b/codegen/service/testdata/client_code.go
index 80d33dcb..825e4fd1 100644
--- a/codegen/service/testdata/client_code.go
+++ b/codegen/service/testdata/client_code.go
@@ -19,6 +19,25 @@ func (c *Client) A(ctx context.Context, p *AType) (err error) {
 }
 `
 
+const UseMethodClient = `// Client is the "UseEndpoint" service client.
+type Client struct {
+	UseEndpointEndpoint goa.Endpoint
+}
+
+// NewClient initializes a "UseEndpoint" service client given the endpoints.
+func NewClient(useEndpoint goa.Endpoint) *Client {
+	return &Client{
+		UseEndpointEndpoint: useEndpoint,
+	}
+}
+
+// UseEndpoint calls the "Use" endpoint of the "UseEndpoint" service.
+func (c *Client) UseEndpoint(ctx context.Context, p string) (err error) {
+	_, err = c.UseEndpointEndpoint(ctx, p)
+	return
+}
+`
+
 const MultipleMethodsClient = `// Client is the "MultipleEndpoints" service client.
 type Client struct {
 	BEndpoint goa.Endpoint
@@ -66,6 +85,29 @@ func (c *Client) NoPayload(ctx context.Context) (err error) {
 }
 `
 
+const WithResultMethodClient = `// Client is the "WithResult" service client.
+type Client struct {
+	AEndpoint goa.Endpoint
+}
+
+// NewClient initializes a "WithResult" service client given the endpoints.
+func NewClient(a goa.Endpoint) *Client {
+	return &Client{
+		AEndpoint: a,
+	}
+}
+
+// A calls the "A" endpoint of the "WithResult" service.
+func (c *Client) A(ctx context.Context) (res *Rtype, err error) {
+	var ires interface{}
+	ires, err = c.AEndpoint(ctx, nil)
+	if err != nil {
+		return
+	}
+	return ires.(*Rtype), nil
+}
+`
+
 const StreamingResultMethodClient = `// Client is the "StreamingResultService" service client.
 type Client struct {
 	StreamingResultMethodEndpoint goa.Endpoint
@@ -166,6 +208,31 @@ func (c *Client) StreamingPayloadNoPayloadMethod(ctx context.Context) (res Strea
 }
 `
 
+const StreamingPayloadNoResultMethodClient = `// Client is the "StreamingPayloadNoResultService" service client.
+type Client struct {
+	StreamingPayloadNoResultMethodEndpoint goa.Endpoint
+}
+
+// NewClient initializes a "StreamingPayloadNoResultService" service client
+// given the endpoints.
+func NewClient(streamingPayloadNoResultMethod goa.Endpoint) *Client {
+	return &Client{
+		StreamingPayloadNoResultMethodEndpoint: streamingPayloadNoResultMethod,
+	}
+}
+
+// StreamingPayloadNoResultMethod calls the "StreamingPayloadNoResultMethod"
+// endpoint of the "StreamingPayloadNoResultService" service.
+func (c *Client) StreamingPayloadNoResultMethod(ctx context.Context) (res StreamingPayloadNoResultMethodClientStream, err error) {
+	var ires interface{}
+	ires, err = c.StreamingPayloadNoResultMethodEndpoint(ctx, nil)
+	if err != nil {
+		return
+	}
+	return ires.(StreamingPayloadNoResultMethodClientStream), nil
+}
+`
+
 const BidirectionalStreamingMethodClient = `// Client is the "BidirectionalStreamingService" service client.
 type Client struct {
 	BidirectionalStreamingMethodEndpoint goa.Endpoint