Repository: goadesign/goa (go)

Issue:
v3: Generated duplicated type factory functions
This design shares a common type between a couple of methods:
```
package design

import (
	. "goa.design/goa/v3/dsl"
)
var _ = API("gbug", func() {
	Server("gbug", func() {
        Host("development", func() {
            URI("http://localhost:8000/gbug")
        })
    })
})

var Item = Type("Item", func() {
    Attribute("name", String, "Name of item")
})

var _ = Service("items", func() {
	HTTP(func() {
		Path("/items")
	})
	Method("listPublic", func() {
		Description("List Public Items")
		Result(ArrayOf(Item))
		HTTP(func() {
			GET("/")
			Response(StatusOK)
		})
	})
	Method("listPrivate", func() {
		Description("List User-private Items")
		Payload(func() {
			Attribute("user", UInt32, "User ID")
		})
		Result(ArrayOf(Item))
		HTTP(func() {
			GET("/{user}")
			Response(StatusOK)
		})
	})
})
```
The generated code ends up with two identical copies for the New* function for this type in ./gen/http/items/server/types.go that look like:
```

// NewItemResponse builds the HTTP response body from the result of the
// "listPublic" endpoint of the "items" service.
func NewItemResponse(res []*items.Item) []*ItemResponse {
	body := make([]*ItemResponse, len(res))
	for i, val := range res {
		body[i] = &ItemResponse{
			Name: val.Name,
		}
	}
	return body
}

// NewItemResponse builds the HTTP response body from the result of the
// "listPrivate" endpoint of the "items" service.
func NewItemResponse(res []*items.Item) []*ItemResponse {
	body := make([]*ItemResponse, len(res))
	for i, val := range res {
		body[i] = &ItemResponse{
			Name: val.Name,
		}
	}
	return body
}
```
The result then doesn't compile.
I have tried to make a single type for the ArrayOf(Item) but it seems to end up with the same problem.



Pull request:
Properly handle array response bodies
Fix #2149

Patch:
diff --git a/http/codegen/server_types.go b/http/codegen/server_types.go
index 0f20de76..d01a834a 100644
--- a/http/codegen/server_types.go
+++ b/http/codegen/server_types.go
@@ -102,7 +102,7 @@ func serverType(genpkg string, svc *expr.HTTPServiceExpr, seen map[string]struct
 		for _, resp := range adata.Result.Responses {
 			for _, tdata := range resp.ServerBody {
 				if generated, ok := data.ServerTypeNames[tdata.Name]; ok && !generated {
-					if tdata.Def != "" && !data.ServerTypeNames[tdata.VarName] {
+					if tdata.Def != "" {
 						sections = append(sections, &codegen.SectionTemplate{
 							Name:   "response-server-body",
 							Source: typeDeclT,
diff --git a/http/codegen/service_data.go b/http/codegen/service_data.go
index 349961a2..ef8c505f 100644
--- a/http/codegen/service_data.go
+++ b/http/codegen/service_data.go
@@ -2090,6 +2090,7 @@ func buildResponseBodyType(body, att *expr.AttributeExpr, e *expr.HTTPEndpointEx
 			var (
 				name    string
 				desc    string
+				rtref   string
 				code    string
 				origin  string
 				err     error
@@ -2099,7 +2100,15 @@ func buildResponseBodyType(body, att *expr.AttributeExpr, e *expr.HTTPEndpointEx
 				svc       = sd.Service
 			)
 			{
-				name = fmt.Sprintf("New%s", codegen.Goify(sd.Scope.GoTypeName(body), true))
+				var rtname string
+				if _, ok := body.Type.(expr.UserType); !ok && !expr.IsPrimitive(body.Type) {
+					rtname = codegen.Goify(e.Name(), true) + "ResponseBody"
+					rtref = rtname
+				} else {
+					rtname = codegen.Goify(sd.Scope.GoTypeName(body), true)
+					rtref = sd.Scope.GoTypeRef(body)
+				}
+				name = fmt.Sprintf("New%s", rtname)
 				desc = fmt.Sprintf("%s builds the HTTP response body from the result of the %q endpoint of the %q service.",
 					name, e.Name(), svc.Name)
 				if view != nil {
@@ -2139,7 +2148,7 @@ func buildResponseBodyType(body, att *expr.AttributeExpr, e *expr.HTTPEndpointEx
 			init = &InitData{
 				Name:                name,
 				Description:         desc,
-				ReturnTypeRef:       sd.Scope.GoTypeRef(body),
+				ReturnTypeRef:       rtref,
 				ReturnTypeAttribute: codegen.Goify(origin, true),
 				ServerCode:          code,
 				ServerArgs:          []*InitArgData{&arg},


Test patch:
diff --git a/http/codegen/testdata/result_encode_functions.go b/http/codegen/testdata/result_encode_functions.go
index e02f9cbf..ddb42228 100644
--- a/http/codegen/testdata/result_encode_functions.go
+++ b/http/codegen/testdata/result_encode_functions.go
@@ -859,7 +859,7 @@ func EncodeMethodBodyPrimitiveArrayUserResponse(encoder func(context.Context, ht
 	return func(ctx context.Context, w http.ResponseWriter, v interface{}) error {
 		res := v.([]*servicebodyprimitivearrayuser.ResultType)
 		enc := encoder(ctx, w)
-		body := NewResultTypeResponse(res)
+		body := NewMethodBodyPrimitiveArrayUserResponseBody(res)
 		w.WriteHeader(http.StatusNoContent)
 		return enc.Encode(body)
 	}
diff --git a/http/codegen/testdata/streaming_code.go b/http/codegen/testdata/streaming_code.go
index 04b6f62a..30b9014a 100644
--- a/http/codegen/testdata/streaming_code.go
+++ b/http/codegen/testdata/streaming_code.go
@@ -815,7 +815,7 @@ func (s *StreamingResultUserTypeArrayMethodServerStream) Send(v []*streamingresu
 		return err
 	}
 	res := v
-	body := NewUserTypeResponse(res)
+	body := NewStreamingResultUserTypeArrayMethodResponseBody(res)
 	return s.conn.WriteJSON(body)
 }
 `
@@ -864,7 +864,7 @@ func (s *StreamingResultUserTypeMapMethodServerStream) Send(v map[string]*stream
 		return err
 	}
 	res := v
-	body := NewMapStringUserTypeResponse(res)
+	body := NewStreamingResultUserTypeMapMethodResponseBody(res)
 	return s.conn.WriteJSON(body)
 }
 `
@@ -3220,7 +3220,7 @@ func (s *BidirectionalStreamingUserTypeArrayMethodServerStream) Send(v []*bidire
 		return err
 	}
 	res := v
-	body := NewResultTypeResponse(res)
+	body := NewBidirectionalStreamingUserTypeArrayMethodResponseBody(res)
 	return s.conn.WriteJSON(body)
 }
 `
@@ -3315,7 +3315,7 @@ func (s *BidirectionalStreamingUserTypeMapMethodServerStream) Send(v map[string]
 		return err
 	}
 	res := v
-	body := NewMapStringResultTypeResponse(res)
+	body := NewBidirectionalStreamingUserTypeMapMethodResponseBody(res)
 	return s.conn.WriteJSON(body)
 }
 `