Repository: goadesign/goa
Pull request #2510 (2020-03-08 22:26:13)

Rewind static view
The 'hasValidation' function would return true in cases where
data structures had required attributes even if requiredness
should not be validated. This could happen client side when
validating a request body or server side when validating a
response body.

Revert change introduced in #2507 where result types used in
results defining a static view were generated as user types
so that the result type always remains the same whether it
is used using static or dynamic views.

Refactor validation code generationfor more clarity.


Patch:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 92343939..f7fab02b 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -7,10 +7,10 @@ jobs:
     runs-on: ubuntu-latest
     steps:
 
-    - name: Set up Go 1.13
+    - name: Set up Go 1.14
       uses: actions/setup-go@v1
       with:
-        go-version: 1.13
+        go-version: 1.14
       id: go
 
     - name: Check out code into the Go module directory
@@ -34,10 +34,10 @@ jobs:
     runs-on: windows-latest
     steps:
 
-    - name: Set up Go 1.13
+    - name: Set up Go 1.14
       uses: actions/setup-go@v1
       with:
-        go-version: 1.13
+        go-version: 1.14
       id: go
 
     - name: Check out code into the Go module directory
diff --git a/codegen/validation.go b/codegen/validation.go
index 7744ee8b..749540ab 100644
--- a/codegen/validation.go
+++ b/codegen/validation.go
@@ -192,121 +192,86 @@ func recurseValidationCode(att *expr.AttributeExpr, attCtx *AttributeContext, re
 		seen[ut.ID()] = buf
 	}
 
+	code := func(ctx *AttributeContext, att *expr.AttributeExpr, tgt, suf string) string {
+		if ut, ok := att.Type.(expr.UserType); ok {
+			if expr.IsPrimitive(ut.Attribute().Type) {
+				return recurseValidationCode(ut.Attribute(), ctx, true, tgt, context+suf, seen).String()
+			} else if hasValidations(attCtx, ut) {
+				var buf bytes.Buffer
+				data := map[string]interface{}{"name": Goify(attCtx.Scope.Name(att, ctx.Pkg), true), "target": tgt}
+				if err := userValT.Execute(&buf, data); err != nil {
+					panic(err) // bug
+				}
+				return fmt.Sprintf("if %s != nil {\n\t%s\n}", tgt, buf.String())
+			}
+		} else {
+			return recurseValidationCode(att, ctx, true, tgt, context+suf, seen).String()
+		}
+		return ""
+	}
+
+	newline := func() {
+		if !first {
+			buf.WriteByte('\n')
+		} else {
+			first = false
+		}
+	}
+
+	// Write validations on attribute if any.
 	validation := ValidationCode(att, attCtx, req, target, context)
 	if validation != "" {
 		buf.WriteString(validation)
 		first = false
 	}
 
-	runUserValT := func(name, target string) string {
-		var buf bytes.Buffer
-		data := map[string]interface{}{
-			"name":   Goify(name, true),
-			"target": target,
-		}
-		if err := userValT.Execute(&buf, data); err != nil {
-			panic(err) // bug
-		}
-		return fmt.Sprintf("if %s != nil {\n\t%s\n}", target, buf.String())
-	}
-
-	if o := expr.AsObject(att.Type); o != nil {
-		for _, nat := range *o {
+	// Recurse down depending on attribute type.
+	switch {
+	case expr.IsObject(att.Type):
+		for _, nat := range *(expr.AsObject(att.Type)) {
 			validation := recurseAttribute(att, attCtx, nat, target, context, seen)
 			if validation != "" {
-				if !first {
-					buf.WriteByte('\n')
-				} else {
-					first = false
-				}
+				newline()
 				buf.WriteString(validation)
 			}
 		}
-	} else if a := expr.AsArray(att.Type); a != nil {
+	case expr.IsArray(att.Type):
+		elem := expr.AsArray(att.Type).ElemType
 		ctx := attCtx
-		if ctx.Pointer && expr.IsPrimitive(a.ElemType.Type) {
+		if ctx.Pointer && expr.IsPrimitive(elem.Type) {
 			// Array elements of primtive type are never pointers
 			ctx = attCtx.Dup()
 			ctx.Pointer = false
 		}
-		var val string
-		{
-			if ut, ok := a.ElemType.Type.(expr.UserType); ok {
-				if expr.IsPrimitive(ut.Attribute().Type) {
-					val = recurseValidationCode(ut.Attribute(), ctx, true, "e", context+"[*]", seen).String()
-				} else if hasValidations(ut) {
-					// For user types, simply call the Validate<TypeName> method
-					val = runUserValT(attCtx.Scope.Name(a.ElemType, ctx.Pkg), "e")
-				}
-			} else {
-				val = recurseValidationCode(a.ElemType, ctx, true, "e", context+"[*]", seen).String()
-			}
-		}
+		val := code(ctx, elem, "e", "[*]")
 		if val != "" {
-			data := map[string]interface{}{
-				"target":     target,
-				"validation": val,
-			}
-			if !first {
-				buf.WriteByte('\n')
-			} else {
-				first = false
-			}
+			newline()
+			data := map[string]interface{}{"target": target, "validation": val}
 			if err := arrayValT.Execute(buf, data); err != nil {
 				panic(err) // bug
 			}
 		}
-	} else if m := expr.AsMap(att.Type); m != nil {
+	case expr.IsMap(att.Type):
+		m := expr.AsMap(att.Type)
 		ctx := attCtx.Dup()
 		ctx.Pointer = false
-		var keyVal string
-		{
-			if ut, ok := m.KeyType.Type.(expr.UserType); ok {
-				if expr.IsPrimitive(ut.Attribute().Type) {
-					keyVal = recurseValidationCode(ut.Attribute(), ctx, true, "k", context+".key", seen).String()
-				} else if hasValidations(ut) {
-					// For user types, simply call the Validate<TypeName> method
-					keyVal = runUserValT(ctx.Scope.Name(m.KeyType, ctx.Pkg), "k")
-				}
-			} else {
-				keyVal = recurseValidationCode(m.KeyType, ctx, true, "k", context+".key", seen).String()
-			}
-			if keyVal != "" {
-				keyVal = "\n" + keyVal
-			}
+		keyVal := code(ctx, m.KeyType, "k", ".key")
+		if keyVal != "" {
+			keyVal = "\n" + keyVal
 		}
-		var valueVal string
-		{
-			if ut, ok := m.ElemType.Type.(expr.UserType); ok {
-				if expr.IsPrimitive(ut.Attribute().Type) {
-					valueVal = recurseValidationCode(ut.Attribute(), ctx, true, "v", context+"[key]", seen).String()
-				} else if hasValidations(ut) {
-					// For user types, simply call the Validate<TypeName> method
-					valueVal = runUserValT(ctx.Scope.Name(m.ElemType, ctx.Pkg), "v")
-				}
-			} else {
-				valueVal = recurseValidationCode(m.ElemType, ctx, true, "v", context+"[key]", seen).String()
-			}
-			if valueVal != "" {
-				valueVal = "\n" + valueVal
-			}
+		valueVal := code(ctx, m.ElemType, "v", "[key]")
+		if valueVal != "" {
+			valueVal = "\n" + valueVal
 		}
 		if keyVal != "" || valueVal != "" {
-			data := map[string]interface{}{
-				"target":          target,
-				"keyValidation":   keyVal,
-				"valueValidation": valueVal,
-			}
-			if !first {
-				buf.WriteByte('\n')
-			} else {
-				first = false
-			}
+			newline()
+			data := map[string]interface{}{"target": target, "keyValidation": keyVal, "valueValidation": valueVal}
 			if err := mapValT.Execute(buf, data); err != nil {
 				panic(err) // bug
 			}
 		}
 	}
+
 	return buf
 }
 
@@ -380,20 +345,33 @@ func recurseAttribute(att *expr.AttributeExpr, attCtx *AttributeContext, nat *ex
 // hasValidations returns true if a UserType contains validations.
 // It recursively iterates through every attribute and returns true if any
 // attribute contains validations.
-func hasValidations(ut expr.UserType) bool {
-	if ut.Attribute().Validation != nil {
+func hasValidations(ctx *AttributeContext, ut expr.UserType) bool {
+	hasVal := func(val *expr.ValidationExpr) bool {
+		if val == nil {
+			return false
+		}
+		if ctx.Pointer {
+			return true
+		}
+		if ctx.UseDefault || ctx.IgnoreRequired {
+			return !val.HasRequiredOnly()
+		}
+		return true
+	}
+
+	if hasVal(ut.Attribute().Validation) {
 		return true
 	}
-	vlds := false
+	found := false
 	done := errors.New("done")
 	Walk(ut.Attribute(), func(a *expr.AttributeExpr) error {
-		if a.Validation != nil {
-			vlds = true
+		if hasVal(a.Validation) {
+			found = true
 			return done
 		}
 		return nil
 	})
-	return vlds
+	return found
 }
 
 // toSlice returns Go code that represents the given slice.
diff --git a/expr/method.go b/expr/method.go
index 87dfb922..fc41b1af 100644
--- a/expr/method.go
+++ b/expr/method.go
@@ -280,16 +280,6 @@ func (m *MethodExpr) Finalize() {
 		m.Result.Finalize()
 		if rt, ok := m.Result.Type.(*ResultTypeExpr); ok {
 			rt.Finalize()
-			// If the method result uses a static view then project
-			// and use the underlying user type as the method result.
-			if v := m.Result.Meta["view"]; len(v) > 0 {
-				p, err := Project(rt, v[0])
-				if err != nil {
-					panic(err) // bug
-				}
-				m.Result.Type = p.UserTypeExpr
-				delete(m.Result.Meta, "view")
-			}
 		}
 	}
 	for _, e := range m.Errors {
diff --git a/go.mod b/go.mod
index 4932d6c6..04aafe54 100644
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,6 @@
 module goa.design/goa/v3
 
-go 1.13
+go 1.14
 
 require (
 	github.com/dimfeld/httppath v0.0.0-20170720192232-ee938bf73598
diff --git a/grpc/codegen/protobuf.go b/grpc/codegen/protobuf.go
index 3f13c35b..3a8f057a 100644
--- a/grpc/codegen/protobuf.go
+++ b/grpc/codegen/protobuf.go
@@ -46,46 +46,39 @@ func protoBufTypeContext(pkg string, scope *codegen.NameScope) *codegen.Attribut
 	return ctx
 }
 
-// makeProtoBufMessage recursively transforms the given attribute expression
-// to generate a valid protocol buffer message definition in the proto file.
-// A protocol buffer message is always a user type in goa v2.
-//
-// NOTE: Protocol buffer does not provide native support for nested
-// arrays/maps (See grpc/docs/FAQ.md)
-//
-// makeProtoBufMessage ensures the resulting attribute is a user type. If the
-// given attribute type is a primitive, array, or a map, it wraps the given
-// attribute under an attribute with name "field" and RPC tag number 1. For,
-// nested arrays/maps, the inner array/map is wrapped into a user type.
+// makeProtoBufMessage ensures the resulting attribute is an object user type so
+// that it can be directly mapped to a protobuf type (protobuf messages must
+// always be objects). If the given attribute type is a primitive, array, or a
+// map, it wraps the given attribute with an object with a single "field"
+// attribute. For nested arrays/maps, the inner array/map is wrapped into a
+// user type.
 func makeProtoBufMessage(att *expr.AttributeExpr, tname string, sd *ServiceData) *expr.AttributeExpr {
 	att = expr.DupAtt(att)
-	switch dt := att.Type.(type) {
-	case expr.Primitive:
+	ut, isut := att.Type.(expr.UserType)
+	switch {
+	case att.Type == expr.Empty:
+		att.Type = &expr.UserTypeExpr{
+			TypeName:      tname,
+			AttributeExpr: &expr.AttributeExpr{Type: &expr.Object{}},
+			UID:           sd.Name + "#" + tname,
+		}
+		return att
+	case expr.IsPrimitive(att.Type):
 		wrapAttr(att, tname, sd)
 		return att
-	case expr.UserType:
-		if dt == expr.Empty {
-			// Empty type must generate a message definition
-			att.Type = &expr.UserTypeExpr{
-				TypeName:      tname,
-				AttributeExpr: &expr.AttributeExpr{Type: &expr.Object{}},
-				UID:           sd.Name + "#" + tname,
-			}
-			return att
-		} else if rt, ok := dt.(*expr.ResultTypeExpr); ok && expr.IsArray(rt) {
-			// result type collection
+	case isut:
+		if expr.IsArray(ut) {
 			wrapAttr(att, tname, sd)
 		}
-	case *expr.Array, *expr.Map:
+	case expr.IsArray(att.Type) || expr.IsMap(att.Type):
 		wrapAttr(att, tname, sd)
-	case *expr.Object:
+	case expr.IsObject(att.Type):
 		att.Type = &expr.UserTypeExpr{
 			TypeName:      tname,
 			AttributeExpr: expr.DupAtt(att),
 			UID:           sd.Name + "#" + tname,
 		}
 	}
-	// wrap nested arrays/maps
 	n := ""
 	makeProtoBufMessageR(att, &n, sd)
 	return att
@@ -93,19 +86,10 @@ func makeProtoBufMessage(att *expr.AttributeExpr, tname string, sd *ServiceData)
 
 // makeProtoBufMessageR is the recursive implementation of makeProtoBufMessage.
 func makeProtoBufMessageR(att *expr.AttributeExpr, tname *string, sd *ServiceData, seen ...map[string]struct{}) {
-	wrap := func(att *expr.AttributeExpr, tname string) {
-		switch dt := att.Type.(type) {
-		case *expr.Array:
-			wrapAttr(att, "ArrayOf"+tname+
-				protoBufify(protoBufMessageDef(dt.ElemType, sd), true), sd)
-		case *expr.Map:
-			wrapAttr(att, tname+"MapOf"+
-				protoBufify(protoBufMessageDef(dt.KeyType, sd), true)+
-				protoBufify(protoBufMessageDef(dt.ElemType, sd), true), sd)
-		}
-	}
-	switch dt := att.Type.(type) {
-	case expr.UserType:
+	ut, isut := att.Type.(expr.UserType)
+
+	// handle infinite recursions
+	if isut {
 		var s map[string]struct{}
 		if len(seen) > 0 {
 			s = seen[0]
@@ -113,24 +97,43 @@ func makeProtoBufMessageR(att *expr.AttributeExpr, tname *string, sd *ServiceDat
 			s = make(map[string]struct{})
 			seen = append(seen, s)
 		}
-		if _, ok := s[dt.ID()]; ok {
+		if _, ok := s[ut.ID()]; ok {
 			return
 		}
-		s[dt.ID()] = struct{}{}
-		if rt, ok := dt.(*expr.ResultTypeExpr); ok && expr.IsArray(rt) {
-			wrapAttr(rt.Attribute(), rt.Name(), sd)
+		s[ut.ID()] = struct{}{}
+	}
+
+	wrap := func(att *expr.AttributeExpr, tname string) {
+		switch {
+		case expr.IsArray(att.Type):
+			wrapAttr(att, "ArrayOf"+tname+
+				protoBufify(protoBufMessageDef(expr.AsArray(att.Type).ElemType, sd), true), sd)
+		case expr.IsMap(att.Type):
+			m := expr.AsMap(att.Type)
+			wrapAttr(att, tname+"MapOf"+
+				protoBufify(protoBufMessageDef(m.KeyType, sd), true)+
+				protoBufify(protoBufMessageDef(m.ElemType, sd), true), sd)
 		}
-		makeProtoBufMessageR(dt.Attribute(), tname, sd, seen...)
-	case *expr.Array:
-		makeProtoBufMessageR(dt.ElemType, tname, sd, seen...)
-		wrap(dt.ElemType, *tname)
-	case *expr.Map:
-		// need not worry about map keys because protocol buffer supports
-		// only primitives as map keys.
-		makeProtoBufMessageR(dt.ElemType, tname, sd, seen...)
-		wrap(dt.ElemType, *tname)
-	case *expr.Object:
-		for _, nat := range *dt {
+	}
+
+	switch {
+	case expr.IsPrimitive(att.Type):
+		return
+	case isut:
+		if expr.IsArray(ut) {
+			wrapAttr(ut.Attribute(), ut.Name(), sd)
+		}
+		makeProtoBufMessageR(ut.Attribute(), tname, sd, seen...)
+	case expr.IsArray(att.Type):
+		ar := expr.AsArray(att.Type)
+		makeProtoBufMessageR(ar.ElemType, tname, sd, seen...)
+		wrap(ar.ElemType, *tname)
+	case expr.IsMap(att.Type):
+		m := expr.AsMap(att.Type)
+		makeProtoBufMessageR(m.ElemType, tname, sd, seen...)
+		wrap(m.ElemType, *tname)
+	case expr.IsObject(att.Type):
+		for _, nat := range *(expr.AsObject(att.Type)) {
 			makeProtoBufMessageR(nat.Attribute, tname, sd, seen...)
 		}
 	}
diff --git a/grpc/codegen/service_data.go b/grpc/codegen/service_data.go
index 9e61b91b..e5963672 100644
--- a/grpc/codegen/service_data.go
+++ b/grpc/codegen/service_data.go
@@ -629,7 +629,7 @@ func (d ServicesData) analyze(gs *expr.GRPCServiceExpr) *ServiceData {
 
 // collectMessages recurses through the attribute to gather all the messages.
 func collectMessages(at *expr.AttributeExpr, sd *ServiceData, seen map[string]struct{}) (data []*service.UserTypeData) {
-	if at == nil {
+	if at == nil || expr.IsPrimitive(at.Type) {
 		return
 	}
 	collect := func(at *expr.AttributeExpr) []*service.UserTypeData {
@@ -640,12 +640,9 @@ func collectMessages(at *expr.AttributeExpr, sd *ServiceData, seen map[string]st
 		if _, ok := seen[dt.Name()]; ok {
 			return nil
 		}
-		if prim := getPrimitive(at); prim != nil {
-			return
-		}
 		att := dt.Attribute()
 		if rt, ok := dt.(*expr.ResultTypeExpr); ok {
-			if a := unwrapAttr(expr.DupAtt(rt.Attribute())); expr.IsArray(a.Type) {
+			if a := unwrapAttr(expr.DupAtt(rt.Attribute())); expr.IsArray(a.Type) && expr.IsObject(rt) {
 				// result type collection
 				att = &expr.AttributeExpr{Type: expr.AsObject(rt)}
 			}
diff --git a/http/codegen/server_types.go b/http/codegen/server_types.go
index 10a83991..04975365 100644
--- a/http/codegen/server_types.go
+++ b/http/codegen/server_types.go
@@ -173,23 +173,19 @@ func serverType(genpkg string, svc *expr.HTTPServiceExpr, seen map[string]struct
 		// request to method payload
 		if init := adata.Payload.Request.PayloadInit; init != nil {
 			sections = append(sections, &codegen.SectionTemplate{
-				Name:   "server-payload-init",
-				Source: serverTypeInitT,
-				Data:   init,
-				FuncMap: map[string]interface{}{
-					"fieldCode": fieldCode,
-				},
+				Name:    "server-payload-init",
+				Source:  serverTypeInitT,
+				Data:    init,
+				FuncMap: map[string]interface{}{"fieldCode": fieldCode},
 			})
 		}
 		if isWebSocketEndpoint(adata) && adata.ServerWebSocket.Payload != nil {
 			if init := adata.ServerWebSocket.Payload.Init; init != nil {
 				sections = append(sections, &codegen.SectionTemplate{
-					Name:   "server-payload-init",
-					Source: serverTypeInitT,
-					Data:   init,
-					FuncMap: map[string]interface{}{
-						"fieldCode": fieldCode,
-					},
+					Name:    "server-payload-init",
+					Source:  serverTypeInitT,
+					Data:    init,
+					FuncMap: map[string]interface{}{"fieldCode": fieldCode},
 				})
 			}
 		}
diff --git a/http/codegen/service_data.go b/http/codegen/service_data.go
index a58204c4..f9c7c32b 100644
--- a/http/codegen/service_data.go
+++ b/http/codegen/service_data.go
@@ -1488,9 +1488,9 @@ func buildResponses(e *expr.HTTPEndpointExpr, result *expr.AttributeExpr, viewed
 						// If a method result uses views (i.e., a result type), we generate
 						// one response body type per view defined in the result type. The
 						// generated body type names are suffixed with the name of the view
-						// (except for "default" view). Constructors are also generated to
-						// create a view-specific body type from the method result. This
-						// makes it possible for the server side to return only the
+						// (except for the "default" view). Constructors are also generated
+						// to create a view-specific body type from the method result.
+						// This makes it possible for the server side to return only the
 						// attributes defined in the view in the response (NOTE: a required
 						// attribute in the result type may not be present in all its views)
 						for _, view := range md.ViewedResult.Views {


Test patch:
diff --git a/codegen/service/testdata/service_code.go b/codegen/service/testdata/service_code.go
index 6a61e026..39f84649 100644
--- a/codegen/service/testdata/service_code.go
+++ b/codegen/service/testdata/service_code.go
@@ -1278,8 +1278,8 @@ var MethodNames = [1]string{"StreamingResultWithExplicitViewMethod"}
 // StreamingResultWithExplicitViewMethodServerStream is the interface a
 // "StreamingResultWithExplicitViewMethod" endpoint server stream must satisfy.
 type StreamingResultWithExplicitViewMethodServerStream interface {
-	// Send streams instances of "MultipleViewsTiny".
-	Send(*MultipleViewsTiny) error
+	// Send streams instances of "MultipleViews".
+	Send(*MultipleViews) error
 	// Close closes the stream.
 	Close() error
 }
@@ -1287,15 +1287,82 @@ type StreamingResultWithExplicitViewMethodServerStream interface {
 // StreamingResultWithExplicitViewMethodClientStream is the interface a
 // "StreamingResultWithExplicitViewMethod" endpoint client stream must satisfy.
 type StreamingResultWithExplicitViewMethodClientStream interface {
-	// Recv reads instances of "MultipleViewsTiny" from the stream.
-	Recv() (*MultipleViewsTiny, error)
+	// Recv reads instances of "MultipleViews" from the stream.
+	Recv() (*MultipleViews, error)
 }
 
-// MultipleViewsTiny is the result type of the
+// MultipleViews is the result type of the
 // StreamingResultWithExplicitViewService service
 // StreamingResultWithExplicitViewMethod method.
-type MultipleViewsTiny struct {
+type MultipleViews struct {
 	A *string
+	B *string
+}
+
+// NewMultipleViews initializes result type MultipleViews from viewed result
+// type MultipleViews.
+func NewMultipleViews(vres *streamingresultwithexplicitviewserviceviews.MultipleViews) *MultipleViews {
+	var res *MultipleViews
+	switch vres.View {
+	case "default", "":
+		res = newMultipleViews(vres.Projected)
+	case "tiny":
+		res = newMultipleViewsTiny(vres.Projected)
+	}
+	return res
+}
+
+// NewViewedMultipleViews initializes viewed result type MultipleViews from
+// result type MultipleViews using the given view.
+func NewViewedMultipleViews(res *MultipleViews, view string) *streamingresultwithexplicitviewserviceviews.MultipleViews {
+	var vres *streamingresultwithexplicitviewserviceviews.MultipleViews
+	switch view {
+	case "default", "":
+		p := newMultipleViewsView(res)
+		vres = &streamingresultwithexplicitviewserviceviews.MultipleViews{Projected: p, View: "default"}
+	case "tiny":
+		p := newMultipleViewsViewTiny(res)
+		vres = &streamingresultwithexplicitviewserviceviews.MultipleViews{Projected: p, View: "tiny"}
+	}
+	return vres
+}
+
+// newMultipleViews converts projected type MultipleViews to service type
+// MultipleViews.
+func newMultipleViews(vres *streamingresultwithexplicitviewserviceviews.MultipleViewsView) *MultipleViews {
+	res := &MultipleViews{
+		A: vres.A,
+		B: vres.B,
+	}
+	return res
+}
+
+// newMultipleViewsTiny converts projected type MultipleViews to service type
+// MultipleViews.
+func newMultipleViewsTiny(vres *streamingresultwithexplicitviewserviceviews.MultipleViewsView) *MultipleViews {
+	res := &MultipleViews{
+		A: vres.A,
+	}
+	return res
+}
+
+// newMultipleViewsView projects result type MultipleViews to projected type
+// MultipleViewsView using the "default" view.
+func newMultipleViewsView(res *MultipleViews) *streamingresultwithexplicitviewserviceviews.MultipleViewsView {
+	vres := &streamingresultwithexplicitviewserviceviews.MultipleViewsView{
+		A: res.A,
+		B: res.B,
+	}
+	return vres
+}
+
+// newMultipleViewsViewTiny projects result type MultipleViews to projected
+// type MultipleViewsView using the "tiny" view.
+func newMultipleViewsViewTiny(res *MultipleViews) *streamingresultwithexplicitviewserviceviews.MultipleViewsView {
+	vres := &streamingresultwithexplicitviewserviceviews.MultipleViewsView{
+		A: res.A,
+	}
+	return vres
 }
 `
 
@@ -1644,8 +1711,8 @@ var MethodNames = [1]string{"StreamingPayloadResultWithExplicitViewMethod"}
 // "StreamingPayloadResultWithExplicitViewMethod" endpoint server stream must
 // satisfy.
 type StreamingPayloadResultWithExplicitViewMethodServerStream interface {
-	// SendAndClose streams instances of "MultipleViewsTiny" and closes the stream.
-	SendAndClose(*MultipleViewsTiny) error
+	// SendAndClose streams instances of "MultipleViews" and closes the stream.
+	SendAndClose(*MultipleViews) error
 	// Recv reads instances of "[]string" from the stream.
 	Recv() ([]string, error)
 }
@@ -1657,15 +1724,82 @@ type StreamingPayloadResultWithExplicitViewMethodClientStream interface {
 	// Send streams instances of "[]string".
 	Send([]string) error
 	// CloseAndRecv stops sending messages to the stream and reads instances of
-	// "MultipleViewsTiny" from the stream.
-	CloseAndRecv() (*MultipleViewsTiny, error)
+	// "MultipleViews" from the stream.
+	CloseAndRecv() (*MultipleViews, error)
 }
 
-// MultipleViewsTiny is the result type of the
+// MultipleViews is the result type of the
 // StreamingPayloadResultWithExplicitViewService service
 // StreamingPayloadResultWithExplicitViewMethod method.
-type MultipleViewsTiny struct {
+type MultipleViews struct {
 	A *string
+	B *string
+}
+
+// NewMultipleViews initializes result type MultipleViews from viewed result
+// type MultipleViews.
+func NewMultipleViews(vres *streamingpayloadresultwithexplicitviewserviceviews.MultipleViews) *MultipleViews {
+	var res *MultipleViews
+	switch vres.View {
+	case "default", "":
+		res = newMultipleViews(vres.Projected)
+	case "tiny":
+		res = newMultipleViewsTiny(vres.Projected)
+	}
+	return res
+}
+
+// NewViewedMultipleViews initializes viewed result type MultipleViews from
+// result type MultipleViews using the given view.
+func NewViewedMultipleViews(res *MultipleViews, view string) *streamingpayloadresultwithexplicitviewserviceviews.MultipleViews {
+	var vres *streamingpayloadresultwithexplicitviewserviceviews.MultipleViews
+	switch view {
+	case "default", "":
+		p := newMultipleViewsView(res)
+		vres = &streamingpayloadresultwithexplicitviewserviceviews.MultipleViews{Projected: p, View: "default"}
+	case "tiny":
+		p := newMultipleViewsViewTiny(res)
+		vres = &streamingpayloadresultwithexplicitviewserviceviews.MultipleViews{Projected: p, View: "tiny"}
+	}
+	return vres
+}
+
+// newMultipleViews converts projected type MultipleViews to service type
+// MultipleViews.
+func newMultipleViews(vres *streamingpayloadresultwithexplicitviewserviceviews.MultipleViewsView) *MultipleViews {
+	res := &MultipleViews{
+		A: vres.A,
+		B: vres.B,
+	}
+	return res
+}
+
+// newMultipleViewsTiny converts projected type MultipleViews to service type
+// MultipleViews.
+func newMultipleViewsTiny(vres *streamingpayloadresultwithexplicitviewserviceviews.MultipleViewsView) *MultipleViews {
+	res := &MultipleViews{
+		A: vres.A,
+	}
+	return res
+}
+
+// newMultipleViewsView projects result type MultipleViews to projected type
+// MultipleViewsView using the "default" view.
+func newMultipleViewsView(res *MultipleViews) *streamingpayloadresultwithexplicitviewserviceviews.MultipleViewsView {
+	vres := &streamingpayloadresultwithexplicitviewserviceviews.MultipleViewsView{
+		A: res.A,
+		B: res.B,
+	}
+	return vres
+}
+
+// newMultipleViewsViewTiny projects result type MultipleViews to projected
+// type MultipleViewsView using the "tiny" view.
+func newMultipleViewsViewTiny(res *MultipleViews) *streamingpayloadresultwithexplicitviewserviceviews.MultipleViewsView {
+	vres := &streamingpayloadresultwithexplicitviewserviceviews.MultipleViewsView{
+		A: res.A,
+	}
+	return vres
 }
 `
 
@@ -1974,4 +2108,70 @@ type MultipleViews struct {
 	A *string
 	B *string
 }
+
+// NewMultipleViews initializes result type MultipleViews from viewed result
+// type MultipleViews.
+func NewMultipleViews(vres *bidirectionalstreamingresultwithexplicitviewserviceviews.MultipleViews) *MultipleViews {
+	var res *MultipleViews
+	switch vres.View {
+	case "default", "":
+		res = newMultipleViews(vres.Projected)
+	case "tiny":
+		res = newMultipleViewsTiny(vres.Projected)
+	}
+	return res
+}
+
+// NewViewedMultipleViews initializes viewed result type MultipleViews from
+// result type MultipleViews using the given view.
+func NewViewedMultipleViews(res *MultipleViews, view string) *bidirectionalstreamingresultwithexplicitviewserviceviews.MultipleViews {
+	var vres *bidirectionalstreamingresultwithexplicitviewserviceviews.MultipleViews
+	switch view {
+	case "default", "":
+		p := newMultipleViewsView(res)
+		vres = &bidirectionalstreamingresultwithexplicitviewserviceviews.MultipleViews{Projected: p, View: "default"}
+	case "tiny":
+		p := newMultipleViewsViewTiny(res)
+		vres = &bidirectionalstreamingresultwithexplicitviewserviceviews.MultipleViews{Projected: p, View: "tiny"}
+	}
+	return vres
+}
+
+// newMultipleViews converts projected type MultipleViews to service type
+// MultipleViews.
+func newMultipleViews(vres *bidirectionalstreamingresultwithexplicitviewserviceviews.MultipleViewsView) *MultipleViews {
+	res := &MultipleViews{
+		A: vres.A,
+		B: vres.B,
+	}
+	return res
+}
+
+// newMultipleViewsTiny converts projected type MultipleViews to service type
+// MultipleViews.
+func newMultipleViewsTiny(vres *bidirectionalstreamingresultwithexplicitviewserviceviews.MultipleViewsView) *MultipleViews {
+	res := &MultipleViews{
+		A: vres.A,
+	}
+	return res
+}
+
+// newMultipleViewsView projects result type MultipleViews to projected type
+// MultipleViewsView using the "default" view.
+func newMultipleViewsView(res *MultipleViews) *bidirectionalstreamingresultwithexplicitviewserviceviews.MultipleViewsView {
+	vres := &bidirectionalstreamingresultwithexplicitviewserviceviews.MultipleViewsView{
+		A: res.A,
+		B: res.B,
+	}
+	return vres
+}
+
+// newMultipleViewsViewTiny projects result type MultipleViews to projected
+// type MultipleViewsView using the "tiny" view.
+func newMultipleViewsViewTiny(res *MultipleViews) *bidirectionalstreamingresultwithexplicitviewserviceviews.MultipleViewsView {
+	vres := &bidirectionalstreamingresultwithexplicitviewserviceviews.MultipleViewsView{
+		A: res.A,
+	}
+	return vres
+}
 `
diff --git a/expr/method_test.go b/expr/method_test.go
index f17da484..a3c5ca41 100644
--- a/expr/method_test.go
+++ b/expr/method_test.go
@@ -20,9 +20,9 @@ func TestMethodExprValidate(t *testing.T) {
 service "InvalidSecuritySchemesService" method "SecureMethod": payload of method "SecureMethod" of service "InvalidSecuritySchemesService" does not define a password attribute, use Password to define one
 service "InvalidSecuritySchemesService" method "SecureMethod": payload of method "SecureMethod" of service "InvalidSecuritySchemesService" does not define a JWT attribute, use Token to define one
 service "InvalidSecuritySchemesService" method "SecureMethod": security scope "not:found" not found in any of the security schemes.
-flow authorization_code: invalid token URL "^example:/token<>": parse ^example:/token<>: first path segment in URL cannot contain colon
-flow authorization_code: invalid authorization URL "http://^authorization": parse http://^authorization: invalid character "^" in host name
-flow authorization_code: invalid refresh URL "http://refresh^": parse http://refresh^: invalid character "^" in host name
+flow authorization_code: invalid token URL "^example:/token<>": parse "^example:/token<>": first path segment in URL cannot contain colon
+flow authorization_code: invalid authorization URL "http://^authorization": parse "http://^authorization": invalid character "^" in host name
+flow authorization_code: invalid refresh URL "http://refresh^": parse "http://refresh^": invalid character "^" in host name
 service "InvalidSecuritySchemesService" method "InheritedSecureMethod": payload of method "InheritedSecureMethod" of service "InvalidSecuritySchemesService" does not define a OAuth2 access token attribute, use AccessToken to define one
 service "InvalidSecuritySchemesService" method "InheritedSecureMethod": payload of method "InheritedSecureMethod" of service "InvalidSecuritySchemesService" does not define an API key attribute, use APIKey to define one
 service "InvalidSecuritySchemesService" method "InheritedSecureMethod": security scope "not:found" not found in any of the security schemes.
diff --git a/grpc/codegen/testdata/response_decoder_code.go b/grpc/codegen/testdata/response_decoder_code.go
index 2b928019..8ba25c53 100644
--- a/grpc/codegen/testdata/response_decoder_code.go
+++ b/grpc/codegen/testdata/response_decoder_code.go
@@ -26,12 +26,22 @@ const ResultWithExplicitViewResponseDecoderCode = `// DecodeMethodMessageResultT
 // the ServiceMessageResultTypeWithExplicitView
 // MethodMessageResultTypeWithExplicitView endpoint.
 func DecodeMethodMessageResultTypeWithExplicitViewResponse(ctx context.Context, v interface{}, hdr, trlr metadata.MD) (interface{}, error) {
+	var view string
+	{
+		if vals := hdr.Get("goa-view"); len(vals) > 0 {
+			view = vals[0]
+		}
+	}
 	message, ok := v.(*service_message_result_type_with_explicit_viewpb.MethodMessageResultTypeWithExplicitViewResponse)
 	if !ok {
 		return nil, goagrpc.ErrInvalidType("ServiceMessageResultTypeWithExplicitView", "MethodMessageResultTypeWithExplicitView", "*service_message_result_type_with_explicit_viewpb.MethodMessageResultTypeWithExplicitViewResponse", v)
 	}
 	res := NewMethodMessageResultTypeWithExplicitViewResult(message)
-	return res, nil
+	vres := &servicemessageresulttypewithexplicitviewviews.RT{Projected: res, View: view}
+	if err := servicemessageresulttypewithexplicitviewviews.ValidateRT(vres); err != nil {
+		return nil, err
+	}
+	return servicemessageresulttypewithexplicitview.NewRT(vres), nil
 }
 `
 
diff --git a/grpc/codegen/testdata/response_encoder_code.go b/grpc/codegen/testdata/response_encoder_code.go
index 73eb26fc..d9e9c121 100644
--- a/grpc/codegen/testdata/response_encoder_code.go
+++ b/grpc/codegen/testdata/response_encoder_code.go
@@ -27,10 +27,12 @@ const ResultWithExplicitViewResponseEncoderCode = `// EncodeMethodMessageResultT
 // the "ServiceMessageResultTypeWithExplicitView" service
 // "MethodMessageResultTypeWithExplicitView" endpoint.
 func EncodeMethodMessageResultTypeWithExplicitViewResponse(ctx context.Context, v interface{}, hdr, trlr *metadata.MD) (interface{}, error) {
-	result, ok := v.(*servicemessageresulttypewithexplicitview.RTTiny)
+	vres, ok := v.(*servicemessageresulttypewithexplicitviewviews.RT)
 	if !ok {
-		return nil, goagrpc.ErrInvalidType("ServiceMessageResultTypeWithExplicitView", "MethodMessageResultTypeWithExplicitView", "*servicemessageresulttypewithexplicitview.RTTiny", v)
+		return nil, goagrpc.ErrInvalidType("ServiceMessageResultTypeWithExplicitView", "MethodMessageResultTypeWithExplicitView", "*servicemessageresulttypewithexplicitviewviews.RT", v)
 	}
+	result := vres.Projected
+	(*hdr).Append("goa-view", vres.View)
 	resp := NewMethodMessageResultTypeWithExplicitViewResponse(result)
 	return resp, nil
 }
diff --git a/grpc/codegen/testdata/streaming_code.go b/grpc/codegen/testdata/streaming_code.go
index c16a2e7f..a6e43132 100644
--- a/grpc/codegen/testdata/streaming_code.go
+++ b/grpc/codegen/testdata/streaming_code.go
@@ -100,26 +100,29 @@ func (s *MethodServerStreamingUserTypeRPCClientStream) SetView(view string) {
 `
 
 var ServerStreamingResultCollectionWithExplicitViewServerSendCode = `// Send streams instances of
-// "service_server_streaming_result_type_collection_with_explicit_viewpb.ResultTypeTinyCollection"
+// "service_server_streaming_result_type_collection_with_explicit_viewpb.ResultTypeCollection"
 // to the "MethodServerStreamingResultTypeCollectionWithExplicitView" endpoint
 // gRPC stream.
-func (s *MethodServerStreamingResultTypeCollectionWithExplicitViewServerStream) Send(res serviceserverstreamingresulttypecollectionwithexplicitview.ResultTypeTinyCollection) error {
-	v := NewResultTypeTinyCollection(res)
+func (s *MethodServerStreamingResultTypeCollectionWithExplicitViewServerStream) Send(res serviceserverstreamingresulttypecollectionwithexplicitview.ResultTypeCollection) error {
+	vres := serviceserverstreamingresulttypecollectionwithexplicitview.NewViewedResultTypeCollection(res, "tiny")
+	v := NewResultTypeCollection(vres.Projected)
 	return s.stream.Send(v)
 }
 `
 
 var ServerStreamingResultCollectionWithExplicitViewClientRecvCode = `// Recv reads instances of
-// "service_server_streaming_result_type_collection_with_explicit_viewpb.ResultTypeTinyCollection"
+// "service_server_streaming_result_type_collection_with_explicit_viewpb.ResultTypeCollection"
 // from the "MethodServerStreamingResultTypeCollectionWithExplicitView"
 // endpoint gRPC stream.
-func (s *MethodServerStreamingResultTypeCollectionWithExplicitViewClientStream) Recv() (serviceserverstreamingresulttypecollectionwithexplicitview.ResultTypeTinyCollection, error) {
-	var res serviceserverstreamingresulttypecollectionwithexplicitview.ResultTypeTinyCollection
+func (s *MethodServerStreamingResultTypeCollectionWithExplicitViewClientStream) Recv() (serviceserverstreamingresulttypecollectionwithexplicitview.ResultTypeCollection, error) {
+	var res serviceserverstreamingresulttypecollectionwithexplicitview.ResultTypeCollection
 	v, err := s.stream.Recv()
 	if err != nil {
 		return res, err
 	}
-	return NewResultTypeTinyCollection(v), nil
+	proj := NewResultTypeCollection(v)
+	vres := serviceserverstreamingresulttypecollectionwithexplicitviewviews.ResultTypeCollection{Projected: proj, View: "tiny"}
+	return serviceserverstreamingresulttypecollectionwithexplicitview.NewResultTypeCollection(vres), nil
 }
 `
 
diff --git a/http/codegen/testdata/openapi_v2/TestSections/explicit-view_file0.golden b/http/codegen/testdata/openapi_v2/TestSections/explicit-view_file0.golden
index 38d76a0f..4ad64e6b 100644
--- a/http/codegen/testdata/openapi_v2/TestSections/explicit-view_file0.golden
+++ b/http/codegen/testdata/openapi_v2/TestSections/explicit-view_file0.golden
@@ -1,1 +1,1 @@
-{"swagger":"2.0","info":{"title":"","version":""},"host":"localhost:80","consumes":["application/json","application/xml","application/gob"],"produces":["application/json","application/xml","application/gob"],"paths":{"/":{"get":{"tags":["testService"],"summary":"testEndpointDefault testService","operationId":"testService#testEndpointDefault","responses":{"204":{"description":"No Content response.","schema":{"$ref":"#/definitions/TestServiceTestEndpointDefaultResponseBody"}}},"schemes":["http"]}},"/tiny":{"get":{"tags":["testService"],"summary":"testEndpointTiny testService","operationId":"testService#testEndpointTiny","responses":{"204":{"description":"No Content response.","schema":{"$ref":"#/definitions/TestServiceTestEndpointTinyResponseBody"}}},"schemes":["http"]}}},"definitions":{"TestServiceTestEndpointDefaultResponseBody":{"title":"TestServiceTestEndpointDefaultResponseBody","type":"object","properties":{"int":{"type":"integer","example":1,"format":"int64"},"string":{"type":"string","example":""}},"example":{"int":1,"string":""}},"TestServiceTestEndpointTinyResponseBody":{"title":"TestServiceTestEndpointTinyResponseBody","type":"object","properties":{"string":{"type":"string","example":""}},"example":{"string":""}}}}
\ No newline at end of file
+{"swagger":"2.0","info":{"title":"","version":""},"host":"localhost:80","consumes":["application/json","application/xml","application/gob"],"produces":["application/json","application/xml","application/gob"],"paths":{"/":{"get":{"tags":["testService"],"summary":"testEndpointDefault testService","operationId":"testService#testEndpointDefault","responses":{"204":{"description":"No Content response.","schema":{"$ref":"#/definitions/TestServiceTestEndpointDefaultResponseBody"}}},"schemes":["http"]}},"/tiny":{"get":{"tags":["testService"],"summary":"testEndpointTiny testService","operationId":"testService#testEndpointTiny","responses":{"204":{"description":"No Content response.","schema":{"$ref":"#/definitions/TestServiceTestEndpointTinyResponseBodyTiny"}}},"schemes":["http"]}}},"definitions":{"TestServiceTestEndpointDefaultResponseBody":{"title":"Mediatype identifier: application/json; view=default","type":"object","properties":{"int":{"type":"integer","example":1,"format":"int64"},"string":{"type":"string","example":""}},"description":"TestEndpointDefaultResponseBody result type (default view)","example":{"int":1,"string":""}},"TestServiceTestEndpointTinyResponseBodyTiny":{"title":"Mediatype identifier: application/json; view=tiny","type":"object","properties":{"string":{"type":"string","example":""}},"description":"TestEndpointTinyResponseBody result type (tiny view) (default view)","example":{"string":""}}}}
\ No newline at end of file
diff --git a/http/codegen/testdata/openapi_v2/TestSections/explicit-view_file1.golden b/http/codegen/testdata/openapi_v2/TestSections/explicit-view_file1.golden
index 614929a7..cdd24f9e 100644
--- a/http/codegen/testdata/openapi_v2/TestSections/explicit-view_file1.golden
+++ b/http/codegen/testdata/openapi_v2/TestSections/explicit-view_file1.golden
@@ -35,12 +35,12 @@ paths:
         "204":
           description: No Content response.
           schema:
-            $ref: '#/definitions/TestServiceTestEndpointTinyResponseBody'
+            $ref: '#/definitions/TestServiceTestEndpointTinyResponseBodyTiny'
       schemes:
       - http
 definitions:
   TestServiceTestEndpointDefaultResponseBody:
-    title: TestServiceTestEndpointDefaultResponseBody
+    title: 'Mediatype identifier: application/json; view=default'
     type: object
     properties:
       int:
@@ -50,15 +50,17 @@ definitions:
       string:
         type: string
         example: ""
+    description: TestEndpointDefaultResponseBody result type (default view)
     example:
       int: 1
       string: ""
-  TestServiceTestEndpointTinyResponseBody:
-    title: TestServiceTestEndpointTinyResponseBody
+  TestServiceTestEndpointTinyResponseBodyTiny:
+    title: 'Mediatype identifier: application/json; view=tiny'
     type: object
     properties:
       string:
         type: string
         example: ""
+    description: TestEndpointTinyResponseBody result type (tiny view) (default view)
     example:
       string: ""
diff --git a/http/codegen/testdata/result_encode_functions.go b/http/codegen/testdata/result_encode_functions.go
index 7474a7ee..ae251708 100644
--- a/http/codegen/testdata/result_encode_functions.go
+++ b/http/codegen/testdata/result_encode_functions.go
@@ -665,9 +665,9 @@ var ResultBodyCollectionExplicitViewEncodeCode = `// EncodeMethodBodyCollectionE
 // MethodBodyCollectionExplicitView endpoint.
 func EncodeMethodBodyCollectionExplicitViewResponse(encoder func(context.Context, http.ResponseWriter) goahttp.Encoder) func(context.Context, http.ResponseWriter, interface{}) error {
 	return func(ctx context.Context, w http.ResponseWriter, v interface{}) error {
-		res := v.(servicebodycollectionexplicitview.ResulttypecollectionTinyCollection)
+		res := v.(servicebodycollectionexplicitviewviews.ResulttypecollectionCollection)
 		enc := encoder(ctx, w)
-		body := NewMethodBodyCollectionExplicitViewResponseBody(res)
+		body := NewResulttypecollectionResponseTinyCollection(res.Projected)
 		w.WriteHeader(http.StatusOK)
 		return enc.Encode(body)
 	}
diff --git a/http/codegen/testdata/streaming_code.go b/http/codegen/testdata/streaming_code.go
index 5a94fc62..26dce361 100644
--- a/http/codegen/testdata/streaming_code.go
+++ b/http/codegen/testdata/streaming_code.go
@@ -409,12 +409,12 @@ func (c *Client) StreamingResultWithExplicitViewMethod() goa.Endpoint {
 }
 `
 
-var StreamingResultWithExplicitViewClientStreamRecvCode = `// Recv reads instances of
-// "streamingresultwithexplicitviewservice.UsertypeExtended" from the
-// "StreamingResultWithExplicitViewMethod" endpoint websocket connection.
-func (s *StreamingResultWithExplicitViewMethodClientStream) Recv() (*streamingresultwithexplicitviewservice.UsertypeExtended, error) {
+var StreamingResultWithExplicitViewClientStreamRecvCode = `// Recv reads instances of "streamingresultwithexplicitviewservice.Usertype"
+// from the "StreamingResultWithExplicitViewMethod" endpoint websocket
+// connection.
+func (s *StreamingResultWithExplicitViewMethodClientStream) Recv() (*streamingresultwithexplicitviewservice.Usertype, error) {
 	var (
-		rv   *streamingresultwithexplicitviewservice.UsertypeExtended
+		rv   *streamingresultwithexplicitviewservice.Usertype
 		body StreamingResultWithExplicitViewMethodResponseBody
 		err  error
 	)
@@ -426,15 +426,18 @@ func (s *StreamingResultWithExplicitViewMethodClientStream) Recv() (*streamingre
 	if err != nil {
 		return rv, err
 	}
-	res := NewStreamingResultWithExplicitViewMethodUsertypeExtendedOK(&body)
-	return res, nil
+	res := NewStreamingResultWithExplicitViewMethodUsertypeOK(&body)
+	vres := &streamingresultwithexplicitviewserviceviews.Usertype{res, "extended"}
+	if err := streamingresultwithexplicitviewserviceviews.ValidateUsertype(vres); err != nil {
+		return rv, goahttp.ErrValidationError("StreamingResultWithExplicitViewService", "StreamingResultWithExplicitViewMethod", err)
+	}
+	return streamingresultwithexplicitviewservice.NewUsertype(vres), nil
 }
 `
 
-var StreamingResultWithExplicitViewServerStreamSendCode = `// Send streams instances of
-// "streamingresultwithexplicitviewservice.UsertypeExtended" to the
-// "StreamingResultWithExplicitViewMethod" endpoint websocket connection.
-func (s *StreamingResultWithExplicitViewMethodServerStream) Send(v *streamingresultwithexplicitviewservice.UsertypeExtended) error {
+var StreamingResultWithExplicitViewServerStreamSendCode = `// Send streams instances of "streamingresultwithexplicitviewservice.Usertype"
+// to the "StreamingResultWithExplicitViewMethod" endpoint websocket connection.
+func (s *StreamingResultWithExplicitViewMethodServerStream) Send(v *streamingresultwithexplicitviewservice.Usertype) error {
 	var err error
 	// Upgrade the HTTP connection to a websocket connection only once. Connection
 	// upgrade is done here so that authorization logic in the endpoint is executed
@@ -453,8 +456,8 @@ func (s *StreamingResultWithExplicitViewMethodServerStream) Send(v *streamingres
 	if err != nil {
 		return err
 	}
-	res := v
-	body := NewStreamingResultWithExplicitViewMethodResponseBody(res)
+	res := streamingresultwithexplicitviewservice.NewViewedUsertype(v, "extended")
+	body := NewStreamingResultWithExplicitViewMethodResponseBodyExtended(res.Projected)
 	return s.conn.WriteJSON(body)
 }
 `
@@ -540,10 +543,10 @@ func (s *StreamingResultCollectionWithViewsMethodClientStream) SetView(view stri
 `
 
 var StreamingResultCollectionWithExplicitViewServerStreamSendCode = `// Send streams instances of
-// "streamingresultcollectionwithexplicitviewservice.UsertypeTinyCollection" to
-// the "StreamingResultCollectionWithExplicitViewMethod" endpoint websocket
+// "streamingresultcollectionwithexplicitviewservice.UsertypeCollection" to the
+// "StreamingResultCollectionWithExplicitViewMethod" endpoint websocket
 // connection.
-func (s *StreamingResultCollectionWithExplicitViewMethodServerStream) Send(v streamingresultcollectionwithexplicitviewservice.UsertypeTinyCollection) error {
+func (s *StreamingResultCollectionWithExplicitViewMethodServerStream) Send(v streamingresultcollectionwithexplicitviewservice.UsertypeCollection) error {
 	var err error
 	// Upgrade the HTTP connection to a websocket connection only once. Connection
 	// upgrade is done here so that authorization logic in the endpoint is executed
@@ -562,8 +565,8 @@ func (s *StreamingResultCollectionWithExplicitViewMethodServerStream) Send(v str
 	if err != nil {
 		return err
 	}
-	res := v
-	body := NewStreamingResultCollectionWithExplicitViewMethodResponseBody(res)
+	res := streamingresultcollectionwithexplicitviewservice.NewViewedUsertypeCollection(v, "tiny")
+	body := NewUsertypeResponseTinyCollection(res.Projected)
 	return s.conn.WriteJSON(body)
 }
 `
@@ -613,12 +616,12 @@ func (c *Client) StreamingResultCollectionWithExplicitViewMethod() goa.Endpoint
 `
 
 var StreamingResultCollectionWithExplicitViewClientStreamRecvCode = `// Recv reads instances of
-// "streamingresultcollectionwithexplicitviewservice.UsertypeTinyCollection"
-// from the "StreamingResultCollectionWithExplicitViewMethod" endpoint
-// websocket connection.
-func (s *StreamingResultCollectionWithExplicitViewMethodClientStream) Recv() (streamingresultcollectionwithexplicitviewservice.UsertypeTinyCollection, error) {
+// "streamingresultcollectionwithexplicitviewservice.UsertypeCollection" from
+// the "StreamingResultCollectionWithExplicitViewMethod" endpoint websocket
+// connection.
+func (s *StreamingResultCollectionWithExplicitViewMethodClientStream) Recv() (streamingresultcollectionwithexplicitviewservice.UsertypeCollection, error) {
 	var (
-		rv   streamingresultcollectionwithexplicitviewservice.UsertypeTinyCollection
+		rv   streamingresultcollectionwithexplicitviewservice.UsertypeCollection
 		body StreamingResultCollectionWithExplicitViewMethodResponseBody
 		err  error
 	)
@@ -630,8 +633,12 @@ func (s *StreamingResultCollectionWithExplicitViewMethodClientStream) Recv() (st
 	if err != nil {
 		return rv, err
 	}
-	res := NewStreamingResultCollectionWithExplicitViewMethodUsertypeTinyCollectionOK(body)
-	return res, nil
+	res := NewStreamingResultCollectionWithExplicitViewMethodUsertypeCollectionOK(body)
+	vres := streamingresultcollectionwithexplicitviewserviceviews.UsertypeCollection{res, "tiny"}
+	if err := streamingresultcollectionwithexplicitviewserviceviews.ValidateUsertypeCollection(vres); err != nil {
+		return rv, goahttp.ErrValidationError("StreamingResultCollectionWithExplicitViewService", "StreamingResultCollectionWithExplicitViewMethod", err)
+	}
+	return streamingresultcollectionwithexplicitviewservice.NewUsertypeCollection(vres), nil
 }
 `
 
@@ -1375,13 +1382,13 @@ func (s *StreamingPayloadResultWithViewsMethodClientStream) SetView(view string)
 `
 
 var StreamingPayloadResultWithExplicitViewServerStreamSendCode = `// SendAndClose streams instances of
-// "streamingpayloadresultwithexplicitviewservice.UsertypeExtended" to the
+// "streamingpayloadresultwithexplicitviewservice.Usertype" to the
 // "StreamingPayloadResultWithExplicitViewMethod" endpoint websocket connection
 // and closes the connection.
-func (s *StreamingPayloadResultWithExplicitViewMethodServerStream) SendAndClose(v *streamingpayloadresultwithexplicitviewservice.UsertypeExtended) error {
+func (s *StreamingPayloadResultWithExplicitViewMethodServerStream) SendAndClose(v *streamingpayloadresultwithexplicitviewservice.Usertype) error {
 	defer s.conn.Close()
-	res := v
-	body := NewStreamingPayloadResultWithExplicitViewMethodResponseBody(res)
+	res := streamingpayloadresultwithexplicitviewservice.NewViewedUsertype(v, "extended")
+	body := NewStreamingPayloadResultWithExplicitViewMethodResponseBodyExtended(res.Projected)
 	return s.conn.WriteJSON(body)
 }
 `
@@ -1432,11 +1439,10 @@ func (s *StreamingPayloadResultWithExplicitViewMethodClientStream) Send(v float3
 var StreamingPayloadResultWithExplicitViewClientStreamRecvCode = `// CloseAndRecv stops sending messages to the
 // "StreamingPayloadResultWithExplicitViewMethod" endpoint websocket connection
 // and reads instances of
-// "streamingpayloadresultwithexplicitviewservice.UsertypeExtended" from the
-// connection.
-func (s *StreamingPayloadResultWithExplicitViewMethodClientStream) CloseAndRecv() (*streamingpayloadresultwithexplicitviewservice.UsertypeExtended, error) {
+// "streamingpayloadresultwithexplicitviewservice.Usertype" from the connection.
+func (s *StreamingPayloadResultWithExplicitViewMethodClientStream) CloseAndRecv() (*streamingpayloadresultwithexplicitviewservice.Usertype, error) {
 	var (
-		rv   *streamingpayloadresultwithexplicitviewservice.UsertypeExtended
+		rv   *streamingpayloadresultwithexplicitviewservice.Usertype
 		body StreamingPayloadResultWithExplicitViewMethodResponseBody
 		err  error
 	)
@@ -1453,8 +1459,12 @@ func (s *StreamingPayloadResultWithExplicitViewMethodClientStream) CloseAndRecv(
 	if err != nil {
 		return rv, err
 	}
-	res := NewStreamingPayloadResultWithExplicitViewMethodUsertypeExtendedOK(&body)
-	return res, nil
+	res := NewStreamingPayloadResultWithExplicitViewMethodUsertypeOK(&body)
+	vres := &streamingpayloadresultwithexplicitviewserviceviews.Usertype{res, "extended"}
+	if err := streamingpayloadresultwithexplicitviewserviceviews.ValidateUsertype(vres); err != nil {
+		return rv, goahttp.ErrValidationError("StreamingPayloadResultWithExplicitViewService", "StreamingPayloadResultWithExplicitViewMethod", err)
+	}
+	return streamingpayloadresultwithexplicitviewservice.NewUsertype(vres), nil
 }
 `
 
@@ -1574,13 +1584,13 @@ func (s *StreamingPayloadResultCollectionWithViewsMethodClientStream) SetView(vi
 `
 
 var StreamingPayloadResultCollectionWithExplicitViewServerStreamSendCode = `// SendAndClose streams instances of
-// "streamingpayloadresultcollectionwithexplicitviewservice.UsertypeTinyCollection"
+// "streamingpayloadresultcollectionwithexplicitviewservice.UsertypeCollection"
 // to the "StreamingPayloadResultCollectionWithExplicitViewMethod" endpoint
 // websocket connection and closes the connection.
-func (s *StreamingPayloadResultCollectionWithExplicitViewMethodServerStream) SendAndClose(v streamingpayloadresultcollectionwithexplicitviewservice.UsertypeTinyCollection) error {
+func (s *StreamingPayloadResultCollectionWithExplicitViewMethodServerStream) SendAndClose(v streamingpayloadresultcollectionwithexplicitviewservice.UsertypeCollection) error {
 	defer s.conn.Close()
-	res := v
-	body := NewStreamingPayloadResultCollectionWithExplicitViewMethodResponseBody(res)
+	res := streamingpayloadresultcollectionwithexplicitviewservice.NewViewedUsertypeCollection(v, "tiny")
+	body := NewUsertypeResponseTinyCollection(res.Projected)
 	return s.conn.WriteJSON(body)
 }
 `
@@ -1633,11 +1643,11 @@ func (s *StreamingPayloadResultCollectionWithExplicitViewMethodClientStream) Sen
 var StreamingPayloadResultCollectionWithExplicitViewClientStreamRecvCode = `// CloseAndRecv stops sending messages to the
 // "StreamingPayloadResultCollectionWithExplicitViewMethod" endpoint websocket
 // connection and reads instances of
-// "streamingpayloadresultcollectionwithexplicitviewservice.UsertypeTinyCollection"
+// "streamingpayloadresultcollectionwithexplicitviewservice.UsertypeCollection"
 // from the connection.
-func (s *StreamingPayloadResultCollectionWithExplicitViewMethodClientStream) CloseAndRecv() (streamingpayloadresultcollectionwithexplicitviewservice.UsertypeTinyCollection, error) {
+func (s *StreamingPayloadResultCollectionWithExplicitViewMethodClientStream) CloseAndRecv() (streamingpayloadresultcollectionwithexplicitviewservice.UsertypeCollection, error) {
 	var (
-		rv   streamingpayloadresultcollectionwithexplicitviewservice.UsertypeTinyCollection
+		rv   streamingpayloadresultcollectionwithexplicitviewservice.UsertypeCollection
 		body StreamingPayloadResultCollectionWithExplicitViewMethodResponseBody
 		err  error
 	)
@@ -1654,8 +1664,12 @@ func (s *StreamingPayloadResultCollectionWithExplicitViewMethodClientStream) Clo
 	if err != nil {
 		return rv, err
 	}
-	res := NewStreamingPayloadResultCollectionWithExplicitViewMethodUsertypeTinyCollectionOK(body)
-	return res, nil
+	res := NewStreamingPayloadResultCollectionWithExplicitViewMethodUsertypeCollectionOK(body)
+	vres := streamingpayloadresultcollectionwithexplicitviewserviceviews.UsertypeCollection{res, "tiny"}
+	if err := streamingpayloadresultcollectionwithexplicitviewserviceviews.ValidateUsertypeCollection(vres); err != nil {
+		return rv, goahttp.ErrValidationError("StreamingPayloadResultCollectionWithExplicitViewService", "StreamingPayloadResultCollectionWithExplicitViewMethod", err)
+	}
+	return streamingpayloadresultcollectionwithexplicitviewservice.NewUsertypeCollection(vres), nil
 }
 `
 
@@ -2559,10 +2573,10 @@ func (s *BidirectionalStreamingResultWithViewsMethodClientStream) SetView(view s
 `
 
 var BidirectionalStreamingResultWithExplicitViewServerStreamSendCode = `// Send streams instances of
-// "bidirectionalstreamingresultwithexplicitviewservice.UsertypeExtended" to
-// the "BidirectionalStreamingResultWithExplicitViewMethod" endpoint websocket
+// "bidirectionalstreamingresultwithexplicitviewservice.Usertype" to the
+// "BidirectionalStreamingResultWithExplicitViewMethod" endpoint websocket
 // connection.
-func (s *BidirectionalStreamingResultWithExplicitViewMethodServerStream) Send(v *bidirectionalstreamingresultwithexplicitviewservice.UsertypeExtended) error {
+func (s *BidirectionalStreamingResultWithExplicitViewMethodServerStream) Send(v *bidirectionalstreamingresultwithexplicitviewservice.Usertype) error {
 	var err error
 	// Upgrade the HTTP connection to a websocket connection only once. Connection
 	// upgrade is done here so that authorization logic in the endpoint is executed
@@ -2581,8 +2595,8 @@ func (s *BidirectionalStreamingResultWithExplicitViewMethodServerStream) Send(v
 	if err != nil {
 		return err
 	}
-	res := v
-	body := NewBidirectionalStreamingResultWithExplicitViewMethodResponseBody(res)
+	res := bidirectionalstreamingresultwithexplicitviewservice.NewViewedUsertype(v, "extended")
+	body := NewBidirectionalStreamingResultWithExplicitViewMethodResponseBodyExtended(res.Projected)
 	return s.conn.WriteJSON(body)
 }
 `
@@ -2633,12 +2647,12 @@ func (s *BidirectionalStreamingResultWithExplicitViewMethodClientStream) Send(v
 `
 
 var BidirectionalStreamingResultWithExplicitViewClientStreamRecvCode = `// Recv reads instances of
-// "bidirectionalstreamingresultwithexplicitviewservice.UsertypeExtended" from
-// the "BidirectionalStreamingResultWithExplicitViewMethod" endpoint websocket
+// "bidirectionalstreamingresultwithexplicitviewservice.Usertype" from the
+// "BidirectionalStreamingResultWithExplicitViewMethod" endpoint websocket
 // connection.
-func (s *BidirectionalStreamingResultWithExplicitViewMethodClientStream) Recv() (*bidirectionalstreamingresultwithexplicitviewservice.UsertypeExtended, error) {
+func (s *BidirectionalStreamingResultWithExplicitViewMethodClientStream) Recv() (*bidirectionalstreamingresultwithexplicitviewservice.Usertype, error) {
 	var (
-		rv   *bidirectionalstreamingresultwithexplicitviewservice.UsertypeExtended
+		rv   *bidirectionalstreamingresultwithexplicitviewservice.Usertype
 		body BidirectionalStreamingResultWithExplicitViewMethodResponseBody
 		err  error
 	)
@@ -2649,8 +2663,12 @@ func (s *BidirectionalStreamingResultWithExplicitViewMethodClientStream) Recv()
 	if err != nil {
 		return rv, err
 	}
-	res := NewBidirectionalStreamingResultWithExplicitViewMethodUsertypeExtendedOK(&body)
-	return res, nil
+	res := NewBidirectionalStreamingResultWithExplicitViewMethodUsertypeOK(&body)
+	vres := &bidirectionalstreamingresultwithexplicitviewserviceviews.Usertype{res, "extended"}
+	if err := bidirectionalstreamingresultwithexplicitviewserviceviews.ValidateUsertype(vres); err != nil {
+		return rv, goahttp.ErrValidationError("BidirectionalStreamingResultWithExplicitViewService", "BidirectionalStreamingResultWithExplicitViewMethod", err)
+	}
+	return bidirectionalstreamingresultwithexplicitviewservice.NewUsertype(vres), nil
 }
 `
 
@@ -2783,10 +2801,10 @@ func (s *BidirectionalStreamingResultCollectionWithViewsMethodClientStream) SetV
 `
 
 var BidirectionalStreamingResultCollectionWithExplicitViewServerStreamSendCode = `// Send streams instances of
-// "bidirectionalstreamingresultcollectionwithexplicitviewservice.UsertypeTinyCollection"
+// "bidirectionalstreamingresultcollectionwithexplicitviewservice.UsertypeCollection"
 // to the "BidirectionalStreamingResultCollectionWithExplicitViewMethod"
 // endpoint websocket connection.
-func (s *BidirectionalStreamingResultCollectionWithExplicitViewMethodServerStream) Send(v bidirectionalstreamingresultcollectionwithexplicitviewservice.UsertypeTinyCollection) error {
+func (s *BidirectionalStreamingResultCollectionWithExplicitViewMethodServerStream) Send(v bidirectionalstreamingresultcollectionwithexplicitviewservice.UsertypeCollection) error {
 	var err error
 	// Upgrade the HTTP connection to a websocket connection only once. Connection
 	// upgrade is done here so that authorization logic in the endpoint is executed
@@ -2805,8 +2823,8 @@ func (s *BidirectionalStreamingResultCollectionWithExplicitViewMethodServerStrea
 	if err != nil {
 		return err
 	}
-	res := v
-	body := NewBidirectionalStreamingResultCollectionWithExplicitViewMethodResponseBody(res)
+	res := bidirectionalstreamingresultcollectionwithexplicitviewservice.NewViewedUsertypeCollection(v, "tiny")
+	body := NewUsertypeResponseTinyCollection(res.Projected)
 	return s.conn.WriteJSON(body)
 }
 `
@@ -2857,12 +2875,12 @@ func (s *BidirectionalStreamingResultCollectionWithExplicitViewMethodClientStrea
 `
 
 var BidirectionalStreamingResultCollectionWithExplicitViewClientStreamRecvCode = `// Recv reads instances of
-// "bidirectionalstreamingresultcollectionwithexplicitviewservice.UsertypeTinyCollection"
+// "bidirectionalstreamingresultcollectionwithexplicitviewservice.UsertypeCollection"
 // from the "BidirectionalStreamingResultCollectionWithExplicitViewMethod"
 // endpoint websocket connection.
-func (s *BidirectionalStreamingResultCollectionWithExplicitViewMethodClientStream) Recv() (bidirectionalstreamingresultcollectionwithexplicitviewservice.UsertypeTinyCollection, error) {
+func (s *BidirectionalStreamingResultCollectionWithExplicitViewMethodClientStream) Recv() (bidirectionalstreamingresultcollectionwithexplicitviewservice.UsertypeCollection, error) {
 	var (
-		rv   bidirectionalstreamingresultcollectionwithexplicitviewservice.UsertypeTinyCollection
+		rv   bidirectionalstreamingresultcollectionwithexplicitviewservice.UsertypeCollection
 		body BidirectionalStreamingResultCollectionWithExplicitViewMethodResponseBody
 		err  error
 	)
@@ -2873,8 +2891,12 @@ func (s *BidirectionalStreamingResultCollectionWithExplicitViewMethodClientStrea
 	if err != nil {
 		return rv, err
 	}
-	res := NewBidirectionalStreamingResultCollectionWithExplicitViewMethodUsertypeTinyCollectionOK(body)
-	return res, nil
+	res := NewBidirectionalStreamingResultCollectionWithExplicitViewMethodUsertypeCollectionOK(body)
+	vres := bidirectionalstreamingresultcollectionwithexplicitviewserviceviews.UsertypeCollection{res, "tiny"}
+	if err := bidirectionalstreamingresultcollectionwithexplicitviewserviceviews.ValidateUsertypeCollection(vres); err != nil {
+		return rv, goahttp.ErrValidationError("BidirectionalStreamingResultCollectionWithExplicitViewService", "BidirectionalStreamingResultCollectionWithExplicitViewMethod", err)
+	}
+	return bidirectionalstreamingresultcollectionwithexplicitviewservice.NewUsertypeCollection(vres), nil
 }
 `