Repository: goadesign/goa
Pull request #2495 (2020-02-20 05:59:52)

Skip encode decode
This PR adds two new DSL functions: `SkipRequestBodyEncodeDecode` and `SkipResponseBodyEncodeDecode`. These functions make it possible to stream HTTP requests and HTTP responses without having to load the body in memory (which is required to marshal data structures and validate the corresponding fields). They are useful to implement streaming of binary files directly to and from disk for example. 

Refer to the function header comments for additional information. The example at https://github.com/goadesign/examples/tree/master/upload_download illustrates how to take advantage of these functions to implement streaming uploads and downloads.


Patch:
diff --git a/codegen/cli/cli.go b/codegen/cli/cli.go
index a0ff7f17..91235e08 100644
--- a/codegen/cli/cli.go
+++ b/codegen/cli/cli.go
@@ -74,6 +74,8 @@ type (
 		Required bool
 		// Example returns a JSON serialized example value.
 		Example string
+		// Default returns the default value if any.
+		Default interface{}
 	}
 
 	// BuildFunctionData contains the data needed to generate a constructor
@@ -314,7 +316,7 @@ func PayloadBuilderSection(buildFunction *BuildFunctionData) *codegen.SectionTem
 // required determines if the flag is required
 // example is an example value for the flag
 //
-func NewFlagData(svcn, en, name, typeName, description string, required bool, example interface{}) *FlagData {
+func NewFlagData(svcn, en, name, typeName, description string, required bool, example, def interface{}) *FlagData {
 	ex := jsonExample(example)
 	fn := goifyTerms(svcn, en, name)
 	return &FlagData{
@@ -325,6 +327,7 @@ func NewFlagData(svcn, en, name, typeName, description string, required bool, ex
 		Description: description,
 		Required:    required,
 		Example:     ex,
+		Default:     def,
 	}
 }
 
@@ -567,7 +570,7 @@ const parseFlagsT = `var (
 		{{ .FullName }}Flags = flag.NewFlagSet("{{ .Name }}", flag.ExitOnError)
 		{{- $sub := . }}
 		{{- range .Flags }}
-		{{ .FullName }}Flag = {{ $sub.FullName }}Flags.String("{{ .Name }}", "{{ if .Required }}REQUIRED{{ end }}", {{ printf "%q" .Description }})
+		{{ .FullName }}Flag = {{ $sub.FullName }}Flags.String("{{ .Name }}", "{{ if .Default }}{{ .Default }}{{ else if .Required }}REQUIRED{{ end }}", {{ printf "%q" .Description }})
 		{{- end }}
 		{{ end }}
 		{{- end }}
diff --git a/codegen/service/client.go b/codegen/service/client.go
index cf732df6..90910ad6 100644
--- a/codegen/service/client.go
+++ b/codegen/service/client.go
@@ -24,6 +24,7 @@ func ClientFile(service *expr.ServiceExpr) *codegen.File {
 		header := codegen.Header(service.Name+" client", svc.PkgName,
 			[]*codegen.ImportSpec{
 				{Path: "context"},
+				{Path: "io"},
 				codegen.GoaImport(""),
 			})
 		def := &codegen.SectionTemplate{
@@ -83,18 +84,23 @@ const serviceClientMethodT = `
 {{- 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 }}
+func (c *{{ .ClientVarName }}) {{ .VarName }}(ctx context.Context, {{ if .PayloadRef }}p {{ .PayloadRef }}{{ end }}{{ if .MethodData.SkipRequestBodyEncodeDecode}}, req io.ReadCloser{{ end }}) ({{ if $resultType }}res {{ $resultType }}, {{ end }}{{ if .MethodData.SkipResponseBodyEncodeDecode }}resp io.ReadCloser, {{ end }}err error) {
+	{{- if or $resultType .MethodData.SkipResponseBodyEncodeDecode }}
 	var ires interface{}
 	{{- end }}
-	{{ if $resultType }}ires{{ else }}_{{ end }}, err = c.{{ .VarName}}Endpoint(ctx, {{ if .PayloadRef }}p{{ else }}nil{{ end }})
-	{{- if not $resultType }}
+	{{ if or $resultType .MethodData.SkipResponseBodyEncodeDecode }}ires{{ else }}_{{ end }}, err = c.{{ .VarName}}Endpoint(ctx, {{ if .MethodData.SkipRequestBodyEncodeDecode }}&{{ .RequestStruct }}{ {{ if .PayloadRef }}Payload: p, {{ end }}Body: req }{{ else if .PayloadRef }}p{{ else }}nil{{ end }})
+	{{- if not (or $resultType .MethodData.SkipResponseBodyEncodeDecode) }}
 	return
 	{{- else }}
 	if err != nil {
 		return
 	}
+		{{- if .MethodData.SkipResponseBodyEncodeDecode }}
+	o := ires.(*{{ .MethodData.ResponseStruct }})
+	return {{ if .ResultRef }}o.Result, {{ end }}o.Body, nil
+		{{- else }}
 	return ires.({{ $resultType }}), nil
+		{{- end }}
 	{{- end }}
 }
 `
diff --git a/codegen/service/endpoint.go b/codegen/service/endpoint.go
index 8bb6e7b9..f85ef8e7 100644
--- a/codegen/service/endpoint.go
+++ b/codegen/service/endpoint.go
@@ -69,6 +69,7 @@ func EndpointFile(genpkg string, service *expr.ServiceExpr) *codegen.File {
 		header := codegen.Header(service.Name+" endpoints", svc.PkgName,
 			[]*codegen.ImportSpec{
 				{Path: "context"},
+				{Path: "io"},
 				{Path: "fmt"},
 				codegen.GoaImport(""),
 				codegen.GoaImport("security"),
@@ -84,7 +85,21 @@ func EndpointFile(genpkg string, service *expr.ServiceExpr) *codegen.File {
 			if m.ServerStream != nil {
 				sections = append(sections, &codegen.SectionTemplate{
 					Name:   "endpoint-input-struct",
-					Source: serviceEndpointInputStructT,
+					Source: serviceEndpointStreamStructT,
+					Data:   m,
+				})
+			}
+			if m.SkipRequestBodyEncodeDecode {
+				sections = append(sections, &codegen.SectionTemplate{
+					Name:   "request-body-struct",
+					Source: serviceRequestBodyStructT,
+					Data:   m,
+				})
+			}
+			if m.SkipResponseBodyEncodeDecode {
+				sections = append(sections, &codegen.SectionTemplate{
+					Name:   "response-body-struct",
+					Source: serviceResponseBodyStructT,
 					Data:   m,
 				})
 			}
@@ -101,12 +116,10 @@ func EndpointFile(genpkg string, service *expr.ServiceExpr) *codegen.File {
 		})
 		for _, m := range data.Methods {
 			sections = append(sections, &codegen.SectionTemplate{
-				Name:   "endpoint-method",
-				Source: serviceEndpointMethodT,
-				Data:   m,
-				FuncMap: map[string]interface{}{
-					"payloadVar": payloadVar,
-				},
+				Name:    "endpoint-method",
+				Source:  serviceEndpointMethodT,
+				Data:    m,
+				FuncMap: map[string]interface{}{"payloadVar": payloadVar},
 			})
 		}
 	}
@@ -173,7 +186,7 @@ func New{{ .VarName }}(s {{ .ServiceVarName }}) *{{ .VarName }} {
 `
 
 // input: endpointMethodData
-const serviceEndpointInputStructT = `{{ printf "%s is the input type of %q endpoint that holds the method payload and the server stream." .ServerStream.EndpointStruct .Name | comment }}
+const serviceEndpointStreamStructT = `{{ printf "%s holds both the payload and the server stream of the %q method." .ServerStream.EndpointStruct .Name | comment }}
 type {{ .ServerStream.EndpointStruct }} struct {
 {{- if .PayloadRef }}
 	{{ comment "Payload is the method payload." }}
@@ -184,12 +197,38 @@ type {{ .ServerStream.EndpointStruct }} struct {
 }
 `
 
+// input: endpointMethodData
+const serviceRequestBodyStructT = `{{ printf "%s holds both the payload and the HTTP request body reader of the %q method." .RequestStruct .Name | comment }}
+type {{ .RequestStruct }} struct {
+{{- if .PayloadRef }}
+	{{ comment "Payload is the method payload." }}
+	Payload {{ .PayloadRef }}
+{{- end }}
+	{{ comment "Body streams the HTTP request body." }}
+	Body io.ReadCloser
+}
+`
+
+// input: endpointMethodData
+const serviceResponseBodyStructT = `{{ printf "%s holds both the result and the HTTP response body reader of the %q method." .ResponseStruct .Name | comment }}
+type {{ .ResponseStruct }} struct {
+{{- if .ResultRef }}
+	{{ comment "Result is the method result." }}
+	Result {{ .ResultRef }}
+{{- end }}
+	{{ comment "Body streams the HTTP response body." }}
+	Body io.ReadCloser
+}
+`
+
 // input: endpointMethodData
 const serviceEndpointMethodT = `{{ printf "New%sEndpoint returns an endpoint function that calls the method %q of service %q." .VarName .Name .ServiceName | comment }}
 func New{{ .VarName }}Endpoint(s {{ .ServiceVarName }}{{ range .Schemes }}, auth{{ .Type }}Fn security.Auth{{ .Type }}Func{{ end }}) goa.Endpoint {
 	return func(ctx context.Context, req interface{}) (interface{}, error) {
-{{- if .ServerStream }}
+{{- if or .ServerStream }}
 		ep := req.(*{{ .ServerStream.EndpointStruct }})
+{{- else if .SkipRequestBodyEncodeDecode }}
+		ep := req.(*{{ .RequestStruct }})
 {{- else if .PayloadRef }}
 		p := req.({{ .PayloadRef }})
 {{- end }}
@@ -300,6 +339,16 @@ func New{{ .VarName }}Endpoint(s {{ .ServiceVarName }}{{ range .Schemes }}, auth
 {{- end }}
 {{- if .ServerStream }}
 	return nil, s.{{ .VarName }}(ctx, {{ if .PayloadRef }}{{ $payload }}, {{ end }}ep.Stream)
+{{- else if .SkipRequestBodyEncodeDecode }}
+	{{- if .SkipResponseBodyEncodeDecode }}
+	{{ if .ResultRef }}res, {{ end }}body, err := s.{{ .VarName }}(ctx, {{ if .PayloadRef }}ep.Payload, {{ end }}ep.Body)
+	if err != nil {
+		return nil, err
+	}
+	return &{{ .ResponseStruct }}{ {{ if .ResultRef }}Result: res, {{ end }}Body: body }, nil
+	{{- else }}
+	return {{ if not .ResultRef }}nil, {{ end }}s.{{ .VarName }}(ctx, {{ if .PayloadRef }}ep.Payload, {{ end }}ep.Body)
+	{{- end }}
 {{- else if .ViewedResult }}
 		res,{{ if not .ViewedResult.ViewName }} view,{{ end }} err := s.{{ .VarName }}(ctx{{ if .PayloadRef }}, {{ $payload }}{{ end }})
 		if err != nil {
@@ -307,10 +356,16 @@ func New{{ .VarName }}Endpoint(s {{ .ServiceVarName }}{{ range .Schemes }}, auth
 		}
 		vres := {{ $.ViewedResult.Init.Name }}(res, {{ if .ViewedResult.ViewName }}{{ printf "%q" .ViewedResult.ViewName }}{{ else }}view{{ end }})
 		return vres, nil
-{{- else if .ResultRef }}
-		return s.{{ .VarName }}(ctx{{ if .PayloadRef }}, {{ $payload }}{{ end }})
 {{- else }}
+	{{- if .SkipResponseBodyEncodeDecode }}
+	{{ if .ResultRef }}res, {{ end }}body, err := s.{{ .VarName }}(ctx{{ if .PayloadRef }}, {{ $payload}}{{ end }})
+	if err != nil {
+		return nil, err
+	}
+	return &{{ .ResponseStruct }}{ {{ if .ResultRef }}Result: res, {{ end }}Body: body }, nil
+	{{- else }}
 	return {{ if not .ResultRef }}nil, {{ end }}s.{{ .VarName }}(ctx{{ if .PayloadRef }}, {{ $payload }}{{ end }})
+	{{- end }}
 {{- end }}
 	}
 }
diff --git a/codegen/service/example_svc.go b/codegen/service/example_svc.go
index 2679b458..e9754fd3 100644
--- a/codegen/service/example_svc.go
+++ b/codegen/service/example_svc.go
@@ -66,9 +66,12 @@ func exampleServiceFile(genpkg string, root *expr.RootExpr, svc *expr.ServiceExp
 		return nil // file already exists, skip it.
 	}
 	specs := []*codegen.ImportSpec{
+		{Path: "io"},
+		{Path: "io/ioutil"},
 		{Path: "context"},
 		{Path: "log"},
 		{Path: "fmt"},
+		{Path: "strings"},
 		{Path: path.Join(genpkg, codegen.SnakeCase(svcName)), Name: data.PkgName},
 		{Path: "goa.design/goa/v3/security"},
 	}
@@ -134,14 +137,14 @@ const (
 	// input: service.Data
 	svcStructT = `{{ printf "%s service example implementation.\nThe example methods log the requests and return zero values." .Name | comment }}
 type {{ .VarName }}srvc struct {
-  logger *log.Logger
+	logger *log.Logger
 }
 `
 
 	// input: service.Data
 	svcInitT = `{{ printf "New%s returns the %s service implementation." .StructName .Name | comment }}
 func New{{ .StructName }}(logger *log.Logger) {{ .PkgName }}.Service {
-  return &{{ .VarName }}srvc{logger}
+	return &{{ .VarName }}srvc{logger}
 }
 `
 
@@ -150,10 +153,18 @@ func New{{ .StructName }}(logger *log.Logger) {{ .PkgName }}.Service {
 {{- if .ServerStream }}
 func (s *{{ .ServiceVarName }}srvc) {{ .VarName }}(ctx context.Context{{ if .PayloadFullRef }}, p {{ .PayloadFullRef }}{{ end }}, stream {{ .StreamInterface }}) (err error) {
 {{- else }}
-func (s *{{ .ServiceVarName }}srvc) {{ .VarName }}(ctx context.Context{{ if .PayloadFullRef }}, p {{ .PayloadFullRef }}{{ end }}) ({{ if .ResultFullRef }}res {{ .ResultFullRef }}, {{ if .ViewedResult }}{{ if not .ViewedResult.ViewName }}view string, {{ end }}{{ end }} {{ end }}err error) {
+func (s *{{ .ServiceVarName }}srvc) {{ .VarName }}(ctx context.Context{{ if .PayloadFullRef }}, p {{ .PayloadFullRef }}{{ end }}{{ if .SkipRequestBodyEncodeDecode }}, req io.ReadCloser{{ end }}) ({{ if .ResultFullRef }}res {{ .ResultFullRef }}, {{ end }}{{ if .SkipResponseBodyEncodeDecode }}resp io.ReadCloser, {{ end }}{{ if .ViewedResult }}{{ if not .ViewedResult.ViewName }}view string, {{ end }}{{ end }}err error) {
+{{- end }}
+{{- if .SkipRequestBodyEncodeDecode }}
+	// req is the HTTP request body stream.
+	defer req.Close()
 {{- end }}
 {{- if and (and .ResultFullRef .ResultIsStruct) (not .ServerStream) }}
-  res = &{{ .ResultFullName }}{}
+	res = &{{ .ResultFullName }}{}
+{{- end }}
+{{- if .SkipResponseBodyEncodeDecode }}
+	// resp is the HTTP response body stream.
+	resp = ioutil.NopCloser(strings.NewReader("{{ .Name }}"))
 {{- end }}
 {{- if .ViewedResult }}
 	{{- if not .ViewedResult.ViewName }}
@@ -164,8 +175,8 @@ func (s *{{ .ServiceVarName }}srvc) {{ .VarName }}(ctx context.Context{{ if .Pay
 		{{- end }}
 	{{- end }}
 {{- end }}
-  s.logger.Print("{{ .ServiceVarName }}.{{ .Name }}")
-  return
+	s.logger.Print("{{ .ServiceVarName }}.{{ .Name }}")
+	return
 }
 `
 )
diff --git a/codegen/service/service.go b/codegen/service/service.go
index 9f446808..08aad266 100644
--- a/codegen/service/service.go
+++ b/codegen/service/service.go
@@ -17,18 +17,17 @@ func File(genpkg string, service *expr.ServiceExpr) *codegen.File {
 		service.Name+" service",
 		svc.PkgName,
 		[]*codegen.ImportSpec{
-			{Path: "context"},
+			codegen.SimpleImport("context"),
+			codegen.SimpleImport("io"),
 			codegen.GoaImport(""),
 			codegen.GoaImport("security"),
-			{Path: genpkg + "/" + svcName + "/" + "views", Name: svc.ViewsPkg},
+			codegen.NewImport(svc.ViewsPkg, genpkg+"/"+svcName+"/views"),
 		})
 	def := &codegen.SectionTemplate{
-		Name:   "service",
-		Source: serviceT,
-		Data:   svc,
-		FuncMap: map[string]interface{}{
-			"streamInterfaceFor": streamInterfaceFor,
-		},
+		Name:    "service",
+		Source:  serviceT,
+		Data:    svc,
+		FuncMap: map[string]interface{}{"streamInterfaceFor": streamInterfaceFor},
 	}
 
 	sections := []*codegen.SectionTemplate{header, def}
@@ -222,7 +221,7 @@ type Service interface {
 	{{- if .ServerStream }}
 		{{ .VarName }}(context.Context{{ if .Payload }}, {{ .PayloadRef }}{{ end }}, {{ .ServerStream.Interface }}) (err error)
 	{{- else }}
-		{{ .VarName }}(context.Context{{ if .Payload }}, {{ .PayloadRef }}{{ end }}) ({{ if .Result }}res {{ .ResultRef }}, {{ if .ViewedResult }}{{ if not .ViewedResult.ViewName }}view string, {{ end }}{{ end }}{{ end }}err error)
+		{{ .VarName }}(context.Context{{ if .Payload }}, {{ .PayloadRef }}{{ end }}{{ if .SkipRequestBodyEncodeDecode }}, io.ReadCloser{{ end }}) ({{ if .Result }}res {{ .ResultRef }}, {{ if .SkipResponseBodyEncodeDecode }}body io.ReadCloser, {{ end }}{{ if .ViewedResult }}{{ if not .ViewedResult.ViewName }}view string, {{ end }}{{ end }}{{ end }}err error)
 	{{- end }}
 {{- end }}
 }
diff --git a/codegen/service/service_data.go b/codegen/service/service_data.go
index 4f644c28..771e3286 100644
--- a/codegen/service/service_data.go
+++ b/codegen/service/service_data.go
@@ -112,6 +112,8 @@ type (
 		PayloadDesc string
 		// PayloadEx is an example of a valid payload value.
 		PayloadEx interface{}
+		// PayloadDefault is the default value of the payload if any.
+		PayloadDefault interface{}
 		// StreamingPayload is the name of the streaming payload type if any.
 		StreamingPayload string
 		// StreamingPayloadDef is the streaming payload type definition if any.
@@ -149,8 +151,23 @@ type (
 		// ClientStream indicates that the service method receives a result
 		// stream or sends a payload result or both.
 		ClientStream *StreamData
-		// StreamKind is the kind of the stream (payload or result or bidirectional).
+		// StreamKind is the kind of the stream (payload or result or
+		// bidirectional).
 		StreamKind expr.StreamKind
+		// SkipRequestBodyEncodeDecode is true if the method payload includes
+		// the raw HTTP request body reader.
+		SkipRequestBodyEncodeDecode bool
+		// SkipResponseBodyEncodeDecode is true if the method result includes
+		// the raw HTTP response body reader.
+		SkipResponseBodyEncodeDecode bool
+		// RequestStruct is the name of the data structure containing the
+		// payload and request body reader when SkipRequestBodyEncodeDecode is
+		// used.
+		RequestStruct string
+		// ResponseStruct is the name of the data structure containing the
+		// result and response body reader when SkipResponseBodyEncodeDecode is
+		// used.
+		ResponseStruct string
 	}
 
 	// StreamData is the data used to generate client and server interfaces that
@@ -185,7 +202,7 @@ type (
 		// reference (if any) and the endpoint server stream. It is set only if the
 		// client sends a normal payload and server streams a result.
 		EndpointStruct string
-		// Kind is the kind of the stream (payload or result or bidirectional).
+		// Kind is the kind of the stream (payload, result or bidirectional).
 		Kind expr.StreamKind
 	}
 
@@ -688,28 +705,21 @@ func buildErrorInitData(er *expr.ErrorExpr, scope *codegen.NameScope) *ErrorInit
 // records the user types needed by the service definition in userTypes.
 func buildMethodData(m *expr.MethodExpr, svcPkgName string, service *expr.ServiceExpr, scope *codegen.NameScope) *MethodData {
 	var (
-		vname        string
-		desc         string
-		payloadName  string
-		payloadDef   string
-		payloadRef   string
-		payloadDesc  string
-		payloadEx    interface{}
-		spayloadName string
-		spayloadDef  string
-		spayloadRef  string
-		spayloadDesc string
-		spayloadEx   interface{}
-		rname        string
-		resultDef    string
-		resultRef    string
-		resultDesc   string
-		resultEx     interface{}
-		errors       []*ErrorInitData
-		reqs         RequirementsData
-		schemes      SchemesData
-		svrStream    *StreamData
-		cliStream    *StreamData
+		vname       string
+		desc        string
+		payloadName string
+		payloadDef  string
+		payloadRef  string
+		payloadDesc string
+		payloadEx   interface{}
+		rname       string
+		resultDef   string
+		resultRef   string
+		resultDesc  string
+		resultEx    interface{}
+		errors      []*ErrorInitData
+		reqs        RequirementsData
+		schemes     SchemesData
 	)
 	vname = scope.Unique(codegen.Goify(m.Name, true), "Endpoint")
 	desc = m.Description
@@ -729,19 +739,6 @@ func buildMethodData(m *expr.MethodExpr, svcPkgName string, service *expr.Servic
 		}
 		payloadEx = m.Payload.Example(expr.Root.API.Random())
 	}
-	if m.StreamingPayload.Type != expr.Empty {
-		spayloadName = scope.GoTypeName(m.StreamingPayload)
-		spayloadRef = scope.GoTypeRef(m.StreamingPayload)
-		if dt, ok := m.StreamingPayload.Type.(expr.UserType); ok {
-			spayloadDef = scope.GoTypeDef(dt.Attribute(), false, true)
-		}
-		spayloadDesc = m.StreamingPayload.Description
-		if spayloadDesc == "" {
-			spayloadDesc = fmt.Sprintf("%s is the streaming payload type of the %s service %s method.",
-				spayloadName, m.Service.Name, m.Name)
-		}
-		spayloadEx = m.StreamingPayload.Example(expr.Root.API.Random())
-	}
 	if m.Result.Type != expr.Empty {
 		rname = scope.GoTypeName(m.Result)
 		resultRef = scope.GoTypeRef(m.Result)
@@ -761,52 +758,6 @@ func buildMethodData(m *expr.MethodExpr, svcPkgName string, service *expr.Servic
 			errors[i] = buildErrorInitData(er, scope)
 		}
 	}
-	if m.IsStreaming() {
-		svrStream = &StreamData{
-			Interface:      vname + "ServerStream",
-			VarName:        scope.Unique(codegen.Goify(m.Name, true), "ServerStream"),
-			EndpointStruct: vname + "EndpointInput",
-			Kind:           m.Stream,
-			SendName:       "Send",
-			SendDesc:       fmt.Sprintf("Send streams instances of %q.", rname),
-			SendTypeName:   rname,
-			SendTypeRef:    resultRef,
-			MustClose:      true,
-		}
-		cliStream = &StreamData{
-			Interface:    vname + "ClientStream",
-			VarName:      scope.Unique(codegen.Goify(m.Name, true), "ClientStream"),
-			Kind:         m.Stream,
-			RecvName:     "Recv",
-			RecvDesc:     fmt.Sprintf("Recv reads instances of %q from the stream.", rname),
-			RecvTypeName: rname,
-			RecvTypeRef:  resultRef,
-		}
-		if m.Stream == expr.ClientStreamKind || m.Stream == expr.BidirectionalStreamKind {
-			switch m.Stream {
-			case expr.ClientStreamKind:
-				if resultRef != "" {
-					svrStream.SendName = "SendAndClose"
-					svrStream.SendDesc = fmt.Sprintf("SendAndClose streams instances of %q and closes the stream.", rname)
-					svrStream.MustClose = false
-					cliStream.RecvName = "CloseAndRecv"
-					cliStream.RecvDesc = fmt.Sprintf("CloseAndRecv stops sending messages to the stream and reads instances of %q from the stream.", rname)
-				} else {
-					cliStream.MustClose = true
-				}
-			case expr.BidirectionalStreamKind:
-				cliStream.MustClose = true
-			}
-			svrStream.RecvName = "Recv"
-			svrStream.RecvDesc = fmt.Sprintf("Recv reads instances of %q from the stream.", spayloadName)
-			svrStream.RecvTypeName = spayloadName
-			svrStream.RecvTypeRef = spayloadRef
-			cliStream.SendName = "Send"
-			cliStream.SendDesc = fmt.Sprintf("Send streams instances of %q.", spayloadName)
-			cliStream.SendTypeName = spayloadName
-			cliStream.SendTypeRef = spayloadRef
-		}
-	}
 	for _, req := range m.Requirements {
 		var rs SchemesData
 		for _, s := range req.Schemes {
@@ -816,33 +767,113 @@ func buildMethodData(m *expr.MethodExpr, svcPkgName string, service *expr.Servic
 		}
 		reqs = append(reqs, &RequirementData{Schemes: rs, Scopes: req.Scopes})
 	}
+	var httpMet *expr.HTTPEndpointExpr
+	if httpSvc := expr.Root.HTTPService(m.Service.Name); httpSvc != nil {
+		httpMet = httpSvc.Endpoint(m.Name)
+	}
+	data := &MethodData{
+		Name:                         m.Name,
+		VarName:                      vname,
+		Description:                  desc,
+		Payload:                      payloadName,
+		PayloadDef:                   payloadDef,
+		PayloadRef:                   payloadRef,
+		PayloadDesc:                  payloadDesc,
+		PayloadEx:                    payloadEx,
+		PayloadDefault:               m.Payload.DefaultValue,
+		Result:                       rname,
+		ResultDef:                    resultDef,
+		ResultRef:                    resultRef,
+		ResultDesc:                   resultDesc,
+		ResultEx:                     resultEx,
+		Errors:                       errors,
+		Requirements:                 reqs,
+		Schemes:                      schemes,
+		StreamKind:                   m.Stream,
+		SkipRequestBodyEncodeDecode:  httpMet != nil && httpMet.SkipRequestBodyEncodeDecode,
+		SkipResponseBodyEncodeDecode: httpMet != nil && httpMet.SkipResponseBodyEncodeDecode,
+		RequestStruct:                vname + "RequestData",
+		ResponseStruct:               vname + "ResponseData",
+	}
+	if m.IsStreaming() {
+		initStreamData(data, m, vname, rname, resultRef, scope)
+	}
+	return data
+}
 
-	return &MethodData{
-		Name:                 m.Name,
-		VarName:              vname,
-		Description:          desc,
-		Payload:              payloadName,
-		PayloadDef:           payloadDef,
-		PayloadRef:           payloadRef,
-		PayloadDesc:          payloadDesc,
-		PayloadEx:            payloadEx,
-		StreamingPayload:     spayloadName,
-		StreamingPayloadDef:  spayloadDef,
-		StreamingPayloadRef:  spayloadRef,
-		StreamingPayloadDesc: spayloadDesc,
-		StreamingPayloadEx:   spayloadEx,
-		Result:               rname,
-		ResultDef:            resultDef,
-		ResultRef:            resultRef,
-		ResultDesc:           resultDesc,
-		ResultEx:             resultEx,
-		Errors:               errors,
-		Requirements:         reqs,
-		Schemes:              schemes,
-		ServerStream:         svrStream,
-		ClientStream:         cliStream,
-		StreamKind:           m.Stream,
+// initStreamData initializes the streaming payload data structures and methods.
+func initStreamData(data *MethodData, m *expr.MethodExpr, vname, rname, resultRef string, scope *codegen.NameScope) {
+	var (
+		spayloadName string
+		spayloadRef  string
+		spayloadDef  string
+		spayloadDesc string
+		spayloadEx   interface{}
+	)
+	if m.StreamingPayload.Type != expr.Empty {
+		spayloadName = scope.GoTypeName(m.StreamingPayload)
+		spayloadRef = scope.GoTypeRef(m.StreamingPayload)
+		if dt, ok := m.StreamingPayload.Type.(expr.UserType); ok {
+			spayloadDef = scope.GoTypeDef(dt.Attribute(), false, true)
+		}
+		spayloadDesc = m.StreamingPayload.Description
+		if spayloadDesc == "" {
+			spayloadDesc = fmt.Sprintf("%s is the streaming payload type of the %s service %s method.",
+				spayloadName, m.Service.Name, m.Name)
+		}
+		spayloadEx = m.StreamingPayload.Example(expr.Root.API.Random())
 	}
+	svrStream := &StreamData{
+		Interface:      vname + "ServerStream",
+		VarName:        scope.Unique(codegen.Goify(m.Name, true), "ServerStream"),
+		EndpointStruct: vname + "EndpointInput",
+		Kind:           m.Stream,
+		SendName:       "Send",
+		SendDesc:       fmt.Sprintf("Send streams instances of %q.", rname),
+		SendTypeName:   rname,
+		SendTypeRef:    resultRef,
+		MustClose:      true,
+	}
+	cliStream := &StreamData{
+		Interface:    vname + "ClientStream",
+		VarName:      scope.Unique(codegen.Goify(m.Name, true), "ClientStream"),
+		Kind:         m.Stream,
+		RecvName:     "Recv",
+		RecvDesc:     fmt.Sprintf("Recv reads instances of %q from the stream.", rname),
+		RecvTypeName: rname,
+		RecvTypeRef:  resultRef,
+	}
+	if m.Stream == expr.ClientStreamKind || m.Stream == expr.BidirectionalStreamKind {
+		switch m.Stream {
+		case expr.ClientStreamKind:
+			if resultRef != "" {
+				svrStream.SendName = "SendAndClose"
+				svrStream.SendDesc = fmt.Sprintf("SendAndClose streams instances of %q and closes the stream.", rname)
+				svrStream.MustClose = false
+				cliStream.RecvName = "CloseAndRecv"
+				cliStream.RecvDesc = fmt.Sprintf("CloseAndRecv stops sending messages to the stream and reads instances of %q from the stream.", rname)
+			} else {
+				cliStream.MustClose = true
+			}
+		case expr.BidirectionalStreamKind:
+			cliStream.MustClose = true
+		}
+		svrStream.RecvName = "Recv"
+		svrStream.RecvDesc = fmt.Sprintf("Recv reads instances of %q from the stream.", spayloadName)
+		svrStream.RecvTypeName = spayloadName
+		svrStream.RecvTypeRef = spayloadRef
+		cliStream.SendName = "Send"
+		cliStream.SendDesc = fmt.Sprintf("Send streams instances of %q.", spayloadName)
+		cliStream.SendTypeName = spayloadName
+		cliStream.SendTypeRef = spayloadRef
+	}
+	data.ClientStream = cliStream
+	data.ServerStream = svrStream
+	data.StreamingPayload = spayloadName
+	data.StreamingPayloadDef = spayloadDef
+	data.StreamingPayloadRef = spayloadDef
+	data.StreamingPayloadDesc = spayloadDesc
+	data.StreamingPayloadEx = spayloadEx
 }
 
 // buildSchemeData builds the scheme data for the given scheme and method expr.
diff --git a/dsl/http.go b/dsl/http.go
index a8df5cfd..25b0e946 100644
--- a/dsl/http.go
+++ b/dsl/http.go
@@ -555,6 +555,77 @@ func MultipartRequest() {
 	e.MultipartRequest = true
 }
 
+// SkipRequestBodyEncodeDecode prevents Goa from generating the request encoding
+// (client) and decoding (server) code. Instead the service method gets direct
+// access to the HTTP body reader. The client method provides a reader from
+// which to stream the request body. This makes it possible to stream requests
+// without requiring the entire content to be loaded in memory for
+// encoding/decoding. Note that the use of this function is incompatible with
+// gRPC and calling it on a method that defines a gRPC transport is an error.
+//
+// SkipRequestBodyEncodeDecode must appear in a HTTP endpoint expression.
+//
+// Example:
+//
+//    var _ = Service("upload", func() {
+//        Method("upload", func() {
+//            Payload(func() {
+//                Attribute("id", String)
+//                Attribute("length", Int)
+//            })
+//            HTTP(func() {
+//                POST("/{id}")
+//                Header("length:Content-Length")
+//                SkipRequestBodyEncodeDecode()
+//            })
+//        })
+//
+func SkipRequestBodyEncodeDecode() {
+	e, ok := eval.Current().(*expr.HTTPEndpointExpr)
+	if !ok {
+		eval.IncompatibleDSL()
+		return
+	}
+	e.SkipRequestBodyEncodeDecode = true
+}
+
+// SkipResponseBodyEncodeDecode prevents Goa from generating the response
+// encoding (server) and decoding (client) code. Instead the service method
+// returns a reader from which to stream the HTTP response body io. The client
+// also gets access to a reader to stream the incoming response body. This makes
+// it possible to stream responses without requiring the entire content to be
+// loaded in memory for encoding/decoding. Note that the use of this function is
+// incompatible with gRPC and calling it on a method that defines a gRPC
+// transport is an error.
+//
+// SkipResponseBodyEncodeDecode must appear in a HTTP endpoint expression.
+//
+// Example:
+//
+//    var _ = Service("download", func() {
+//        Method("download", func() {
+//            Payload(String)
+//            Result(func() {
+//                Attribute("length", Int)
+//            })
+//            HTTP(func() {
+//                POST("/{id}")
+//                SkipResponseBodyEncodeDecode()
+//                Response(StatusOK, func() {
+//                    Header("length:Content-Length")
+//                })
+//            })
+//        })
+//
+func SkipResponseBodyEncodeDecode() {
+	e, ok := eval.Current().(*expr.HTTPEndpointExpr)
+	if !ok {
+		eval.IncompatibleDSL()
+		return
+	}
+	e.SkipResponseBodyEncodeDecode = true
+}
+
 // Body describes a HTTP request or response body.
 //
 // Body must appear in a Method HTTP expression to define the request body or in
diff --git a/expr/grpc_endpoint.go b/expr/grpc_endpoint.go
index d2ff37c8..12931f60 100644
--- a/expr/grpc_endpoint.go
+++ b/expr/grpc_endpoint.go
@@ -410,7 +410,7 @@ func validateRPCTags(fields *Object, e *GRPCEndpointExpr) *eval.ValidationErrors
 	foundRPC := make(map[string]string)
 	for _, nat := range *fields {
 		if tag, ok := nat.Attribute.FieldTag(); !ok {
-			verr.Add(e, "attribute %q does not have \"rpc:tag\" defined in the meta", nat.Name)
+			verr.Add(e, "attribute %q does not have \"rpc:tag\" defined in the meta, use \"Field\" to define the attribute of a type used in a gRPC method", nat.Name)
 		} else if a, ok := foundRPC[tag]; ok {
 			verr.Add(e, "field number %s in attribute %q already exists for attribute %q", tag, nat.Name, a)
 		} else {
diff --git a/expr/http_endpoint.go b/expr/http_endpoint.go
index 6bcd0359..7ccbddc2 100644
--- a/expr/http_endpoint.go
+++ b/expr/http_endpoint.go
@@ -43,6 +43,14 @@ type (
 		// StreamingBody describes the body transferred through the websocket
 		// stream.
 		StreamingBody *AttributeExpr
+		// SkipRequestBodyEncodeDecode indicates that the service method accepts
+		// a reader and that the client provides a reader to stream the request
+		// body.
+		SkipRequestBodyEncodeDecode bool
+		// SkipResponseBodyEncodeDecode indicates that the service method
+		// returns a reader and that the client accepts a reader to stream the
+		// response body.
+		SkipResponseBodyEncodeDecode bool
 		// Responses is the list of all the possible success HTTP
 		// responses.
 		Responses []*HTTPResponseExpr
@@ -269,6 +277,41 @@ func (e *HTTPEndpointExpr) Validate() error {
 		verr.Add(e, "Endpoint name cannot be empty")
 	}
 
+	// SkipRequestBodyEncodeDecode is not compatible with gRPC or WebSocket
+	if e.SkipRequestBodyEncodeDecode {
+		if s := Root.API.GRPC.Service(e.Service.Name()); s != nil {
+			if s.Endpoint(e.Name()) != nil {
+				verr.Add(e, "Endpoint cannot use SkipRequestBodyEncodeDecode and define a gRPC transport.")
+			}
+		}
+		if e.MethodExpr.IsPayloadStreaming() {
+			verr.Add(e, "Endpoint cannot use SkipRequestBodyEncodeDecode when method defines a StreamingPayload.")
+		}
+		if e.MethodExpr.IsResultStreaming() {
+			verr.Add(e, "Endpoint cannot use SkipRequestBodyEncodeDecode when method defines a StreamingResult. Use SkipResponseBodyEncodeDecode instead.")
+		}
+	}
+
+	// SkipResponseBodyEncodeDecode is not compatible with gRPC or WebSocket.
+	if e.SkipResponseBodyEncodeDecode {
+		if s := Root.API.GRPC.Service(e.Service.Name()); s != nil {
+			if s.Endpoint(e.Name()) != nil {
+				verr.Add(e, "Endpoint response cannot use SkipResponseBodyEncodeDecode and define a gRPC transport.")
+			}
+		}
+		if e.MethodExpr.IsPayloadStreaming() {
+			verr.Add(e, "Endpoint cannot use SkipResponseBodyEncodeDecode when method defines a StreamingPayload. Use SkipRequestBodyEncodeDecode instead.")
+		}
+		if e.MethodExpr.IsResultStreaming() {
+			verr.Add(e, "Endpoint cannot use SkipResponseBodyEncodeDecode when method defines a StreamingResult.")
+		}
+		if rt, ok := e.MethodExpr.Result.Type.(*ResultTypeExpr); ok {
+			if len(rt.Views) > 1 {
+				verr.Add(e, "Endpoint cannot use SkipResponseBodyEncodeDecode when method result type defines multiple views.")
+			}
+		}
+	}
+
 	// Validate routes
 
 	// Routes cannot be empty
@@ -326,15 +369,16 @@ func (e *HTTPEndpointExpr) Validate() error {
 		} else {
 			hasTags = true
 		}
-		if r.StatusCode < 400 && e.MethodExpr.Stream == ServerStreamKind {
-			if successResp {
-				verr.Add(r, "Multiple success response defined for a streaming endpoint. At most one success response can be defined for a streaming endpoint.")
-			} else {
-				successResp = true
-			}
-			if r.Body != nil && r.Body.Type == Empty {
-				verr.Add(r, "Response body is empty but the endpoint uses streaming result. Response body cannot be empty for a success response if endpoint defines streaming result.")
+		if r.StatusCode < 400 {
+			if successResp && e.MethodExpr.Stream == ServerStreamKind {
+				verr.Add(r, "At most one success response can be defined for a streaming endpoint.")
+				if r.Body != nil && r.Body.Type == Empty {
+					verr.Add(r, "Response body empty but endpoint defines streaming WebSocket response.")
+				}
+			} else if successResp && e.SkipResponseBodyEncodeDecode {
+				verr.Add(r, "At most one success response can be defined for a endpoint using SkipResponseBodyEncodeDecode.")
 			}
+			successResp = true
 		}
 	}
 	if hasTags && allTagged {
@@ -351,6 +395,9 @@ func (e *HTTPEndpointExpr) Validate() error {
 	// Validate body attribute (required fields exist etc.)
 	if e.Body != nil {
 		verr.Merge(e.Body.Validate("HTTP endpoint payload", e))
+		if e.SkipRequestBodyEncodeDecode {
+			verr.Add(e, "Cannot define a request body when using SkipRequestBodyEncodeDecode.")
+		}
 	}
 
 	// Validate errors
@@ -359,6 +406,10 @@ func (e *HTTPEndpointExpr) Validate() error {
 	}
 
 	// Validate definitions of params, headers and bodies against definition of payload
+	var (
+		hasParams  = !e.Params.IsEmpty()
+		hasHeaders = !e.Headers.IsEmpty()
+	)
 	if isEmpty(e.MethodExpr.Payload) {
 		if e.MapQueryParams != nil {
 			verr.Add(e, "MapParams is set but Payload is not defined")
@@ -378,18 +429,13 @@ func (e *HTTPEndpointExpr) Validate() error {
 		if e.MapQueryParams != nil {
 			verr.Add(e, "MapParams is set but Payload type is array. Payload type must be map or an object with a map attribute")
 		}
-		var hasParams, hasHeaders bool
-		if !e.Params.IsEmpty() {
-			if e.MultipartRequest {
-				verr.Add(e, "Payload type is array but HTTP endpoint defines MultipartRequest and route/query string parameters. At most one of these must be defined.")
-			}
-			hasParams = true
+		if hasParams && e.MultipartRequest {
+			verr.Add(e, "Payload type is array but HTTP endpoint defines MultipartRequest and route/query string parameters. At most one of these must be defined.")
 		}
-		if !e.Headers.IsEmpty() {
+		if hasHeaders {
 			if e.MultipartRequest {
 				verr.Add(e, "Payload type is array but HTTP endpoint defines MultipartRequest and headers. At most one of these must be defined.")
 			}
-			hasHeaders = true
 			if hasParams {
 				verr.Add(e, "Payload type is array but HTTP endpoint defines both route or query string parameters and headers. At most one parameter or header must be defined and it must be of type array.")
 			}
@@ -411,6 +457,9 @@ func (e *HTTPEndpointExpr) Validate() error {
 				verr.Add(e, "Payload type is array but HTTP endpoint defines both a body and headers. At most one of these must be defined and it must be an array.")
 			}
 		}
+		if !hasParams && !hasHeaders && e.SkipRequestBodyEncodeDecode {
+			verr.Add(e, "Payload type is array but HTTP endpoint uses SkipRequestBodyEncodeDecode and does not define headers or params.")
+		}
 	}
 
 	if pMap := AsMap(e.MethodExpr.Payload.Type); pMap != nil {
@@ -431,12 +480,8 @@ func (e *HTTPEndpointExpr) Validate() error {
 				verr.Add(e, "MapParams is set and Payload type is map. But array elements in payload element type must be primitive")
 			}
 		}
-		var hasParams bool
-		if !e.Params.IsEmpty() {
-			if e.MultipartRequest {
-				verr.Add(e, "Payload type is map but HTTP endpoint defines MultipartRequest and route/query string parameters. At most one of these must be defined.")
-			}
-			hasParams = true
+		if hasParams && e.MultipartRequest {
+			verr.Add(e, "Payload type is map but HTTP endpoint defines MultipartRequest and route/query string parameters. At most one of these must be defined.")
 		}
 		if e.Body != nil && e.Body.Type != Empty {
 			if e.MultipartRequest {
@@ -449,6 +494,9 @@ func (e *HTTPEndpointExpr) Validate() error {
 				verr.Add(e, "Payload type is map but HTTP endpoint defines both a body and route or query string parameters. At most one of these must be defined and it must be a map.")
 			}
 		}
+		if !hasParams && e.SkipRequestBodyEncodeDecode {
+			verr.Add(e, "Payload type is map but HTTP endpoint uses SkipRequestBodyEncodeDecode and does not define headers.")
+		}
 	}
 
 	if IsObject(e.MethodExpr.Payload.Type) {
@@ -481,6 +529,13 @@ func (e *HTTPEndpointExpr) Validate() error {
 		}
 	}
 
+	if e.SkipRequestBodyEncodeDecode {
+		body := httpRequestBody(e)
+		if body.Type != Empty {
+			verr.Add(e, "HTTP endpoint request body must be empty when using SkipRequestBodyEncodeDecode but not all method payload attributes are mapped to headers and params. Make sure to define Headers and Params as needed.")
+		}
+	}
+
 	return verr
 }
 
@@ -760,9 +815,9 @@ func (r *RouteExpr) Validate() *eval.ValidationErrors {
 	}
 
 	// For streaming endpoints, websockets does not support verbs other than GET
-	if r.Endpoint.MethodExpr.IsStreaming() {
+	if r.Endpoint.MethodExpr.IsStreaming() && len(r.Endpoint.Responses) > 0 {
 		if r.Method != "GET" {
-			verr.Add(r, "Streaming endpoint supports only \"GET\" method. Got %q.", r.Method)
+			verr.Add(r, "WebSocket endpoint supports only \"GET\" method. Got %q.", r.Method)
 		}
 	}
 	return verr
diff --git a/expr/http_response.go b/expr/http_response.go
index a31adc20..e517a50f 100644
--- a/expr/http_response.go
+++ b/expr/http_response.go
@@ -123,25 +123,16 @@ func (r *HTTPResponseExpr) Validate(e *HTTPEndpointExpr) *eval.ValidationErrors
 
 	if r.StatusCode == 0 {
 		verr.Add(r, "HTTP response status not defined")
-	} else if !bodyAllowedForStatus(r.StatusCode) && r.bodyExists() && !e.MethodExpr.IsStreaming() {
-		verr.Add(r, "Response body defined for status code %d which does not allow response body.", r.StatusCode)
-	}
-
-	if e.MethodExpr.Result.Type == Empty {
-		if !r.Headers.IsEmpty() {
-			verr.Add(r, "response defines headers but result is empty")
+	} else if !bodyAllowedForStatus(r.StatusCode) && !e.MethodExpr.IsStreaming() {
+		ep, ok := r.Parent.(*HTTPEndpointExpr)
+		if ok && httpResponseBody(ep, r).Type != Empty {
+			verr.Add(r, "Response body defined for status code %d which does not allow response body.", r.StatusCode)
 		}
-		return verr
 	}
 
-	rt, isrt := e.MethodExpr.Result.Type.(*ResultTypeExpr)
-	var inview string
-	if isrt {
-		inview = " all views in"
-	}
-
-	// text/html can only encode strings so make sure there isn't an explicit conflict with the content-type and response.
-	if r.ContentType == "text/html" || r.ContentType == "text/plain" {
+	// text/html and text/plain can only encode strings so make sure there isn't
+	// an explicit conflict with the content-type and response.
+	if (r.ContentType == "text/html" || r.ContentType == "text/plain") && !e.SkipRequestBodyEncodeDecode {
 		if e.MethodExpr.Result.Type != nil && e.MethodExpr.Result.Type != String && e.MethodExpr.Result.Type != Bytes && r.Body == nil {
 			verr.Add(r, fmt.Sprintf("Result type must be String or Bytes when ContentType is '%s'", r.ContentType))
 		}
@@ -150,30 +141,36 @@ func (r *HTTPResponseExpr) Validate(e *HTTPEndpointExpr) *eval.ValidationErrors
 		}
 	}
 
+	rt, isrt := e.MethodExpr.Result.Type.(*ResultTypeExpr)
 	resultAttributeType := func(name string) DataType {
 		if !IsObject(e.MethodExpr.Result.Type) {
 			return nil
 		}
-		if !isrt {
-			att := e.MethodExpr.Result.Find(name)
-			if att == nil || att.Type == nil {
-				return nil
+		if isrt {
+			if v, ok := e.MethodExpr.Result.Meta["view"]; ok {
+				v := rt.View(v[0])
+				if v == nil {
+					return nil
+				}
+				return v.AttributeExpr.Find(name).Type
 			}
-			return att.Type
-		}
-		if v, ok := e.MethodExpr.Result.Meta["view"]; ok {
-			v := rt.View(v[0])
-			if v == nil {
-				return nil
+			for _, v := range rt.Views {
+				if !rt.ViewHasAttribute(v.Name, name) {
+					return nil
+				}
 			}
-			return v.AttributeExpr.Find(name).Type
 		}
-		for _, v := range rt.Views {
-			if !rt.ViewHasAttribute(v.Name, name) {
-				return nil
-			}
+		att := e.MethodExpr.Result.Find(name)
+		if att == nil || att.Type == nil {
+			// nil != nil
+			return nil
 		}
-		return e.MethodExpr.Result.Find(name).Type
+		return att.Type
+	}
+
+	var inview string
+	if isrt {
+		inview = " all views of"
 	}
 
 	if !r.Headers.IsEmpty() {
@@ -205,6 +202,9 @@ func (r *HTTPResponseExpr) Validate(e *HTTPEndpointExpr) *eval.ValidationErrors
 	}
 	if r.Body != nil {
 		verr.Merge(r.Body.Validate("HTTP response body", r))
+		if e.SkipResponseBodyEncodeDecode {
+			verr.Add(r, "Cannot define a response body when endpoint uses SkipResponseBodyEncodeDecode.")
+		}
 		if att, ok := r.Body.Meta["origin:attribute"]; ok {
 			if resultAttributeType(att[0]) == nil {
 				verr.Add(r, "body %q has no equivalent attribute in%s result type", att[0], inview)
@@ -216,6 +216,11 @@ func (r *HTTPResponseExpr) Validate(e *HTTPEndpointExpr) *eval.ValidationErrors
 				}
 			}
 		}
+	} else if e.SkipResponseBodyEncodeDecode {
+		body := httpResponseBody(e, r)
+		if body.Type != Empty {
+			verr.Add(e, "HTTP endpoint response body must be empty when using SkipResponseBodyEncodeDecode. Make sure to define Headers as needed.")
+		}
 	}
 	return verr
 }
@@ -299,10 +304,3 @@ func bodyAllowedForStatus(status int) bool {
 	}
 	return true
 }
-
-// bodyExists returns true if a response body is defined in the
-// response expression via Body() or Result() in the method expression.
-func (r *HTTPResponseExpr) bodyExists() bool {
-	ep, ok := r.Parent.(*HTTPEndpointExpr)
-	return ok && httpResponseBody(ep, r).Type != Empty
-}
diff --git a/expr/method.go b/expr/method.go
index fc97affe..fc41b1af 100644
--- a/expr/method.go
+++ b/expr/method.go
@@ -310,7 +310,7 @@ func (m *MethodExpr) Finalize() {
 
 // IsStreaming determines whether the method streams payload or result.
 func (m *MethodExpr) IsStreaming() bool {
-	return m.Stream != 0 && m.Stream != NoStreamKind
+	return m.IsPayloadStreaming() || m.IsResultStreaming()
 }
 
 // IsPayloadStreaming determines whether the method streams payload.
@@ -318,6 +318,11 @@ func (m *MethodExpr) IsPayloadStreaming() bool {
 	return m.Stream == ClientStreamKind || m.Stream == BidirectionalStreamKind
 }
 
+// IsResultStreaming determines whether the method streams payload.
+func (m *MethodExpr) IsResultStreaming() bool {
+	return m.Stream == ServerStreamKind || m.Stream == BidirectionalStreamKind
+}
+
 // helper function that duplicates just enough of a security expression so that
 // its scheme names can be overridden without affecting the original.
 func copyReqs(reqs []*SecurityExpr) []*SecurityExpr {
diff --git a/expr/root.go b/expr/root.go
index ac93b047..8dfa24bd 100644
--- a/expr/root.go
+++ b/expr/root.go
@@ -1,9 +1,11 @@
 package expr
 
 import (
+	"fmt"
 	"sort"
 
 	"goa.design/goa/v3/eval"
+	goa "goa.design/goa/v3/pkg"
 )
 
 // Root is the root object built by the DSL.
@@ -143,6 +145,8 @@ func (r *RootExpr) Packages() []string {
 	return []string{
 		"goa.design/goa/v3/expr",
 		"goa.design/goa/v3/dsl",
+		fmt.Sprintf("goa.design/goa/v3@%s/expr", goa.Version()),
+		fmt.Sprintf("goa.design/goa/v3@%s/dsl", goa.Version()),
 	}
 }
 
diff --git a/grpc/codegen/client_cli.go b/grpc/codegen/client_cli.go
index 7009e4cf..3e32269f 100644
--- a/grpc/codegen/client_cli.go
+++ b/grpc/codegen/client_cli.go
@@ -155,7 +155,7 @@ func makeFlags(e *EndpointData, args []*InitArgData) ([]*cli.FlagData, *cli.Buil
 			FieldName: arg.FieldName,
 		}
 
-		f := cli.NewFlagData(e.ServiceName, e.Method.Name, arg.Name, arg.TypeName, arg.Description, arg.Required, arg.Example)
+		f := cli.NewFlagData(e.ServiceName, e.Method.Name, arg.Name, arg.TypeName, arg.Description, arg.Required, arg.Example, arg.DefaultValue)
 		flags[i] = f
 		params[i] = f.FullName
 		code, chek := cli.FieldLoadCode(f, arg.Name, arg.TypeName, arg.Validate, arg.DefaultValue)
diff --git a/http/codegen/client.go b/http/codegen/client.go
index e02e3872..f967559b 100644
--- a/http/codegen/client.go
+++ b/http/codegen/client.go
@@ -9,20 +9,25 @@ import (
 	"goa.design/goa/v3/expr"
 )
 
-// ClientFiles returns the client HTTP transport files.
+// ClientFiles returns the generated HTTP client files.
 func ClientFiles(genpkg string, root *expr.RootExpr) []*codegen.File {
-	fw := make([]*codegen.File, 2*len(root.API.HTTP.Services))
-	for i, r := range root.API.HTTP.Services {
-		fw[i] = client(genpkg, r)
+	var files []*codegen.File
+	for _, svc := range root.API.HTTP.Services {
+		files = append(files, clientFile(genpkg, svc))
+		if f := websocketClientFile(genpkg, svc); f != nil {
+			files = append(files, f)
+		}
 	}
-	for i, r := range root.API.HTTP.Services {
-		fw[i+len(root.API.HTTP.Services)] = clientEncodeDecode(genpkg, r)
+	for _, svc := range root.API.HTTP.Services {
+		if f := clientEncodeDecodeFile(genpkg, svc); f != nil {
+			files = append(files, f)
+		}
 	}
-	return fw
+	return files
 }
 
-// client returns the client HTTP transport file
-func client(genpkg string, svc *expr.HTTPServiceExpr) *codegen.File {
+// clientFile returns the client HTTP transport file
+func clientFile(genpkg string, svc *expr.HTTPServiceExpr) *codegen.File {
 	data := HTTPServices.Get(svc.Name())
 	svcName := codegen.SnakeCase(data.Service.VarName)
 	path := filepath.Join(codegen.Gendir, "http", svcName, "client", "client.go")
@@ -36,7 +41,6 @@ func client(genpkg string, svc *expr.HTTPServiceExpr) *codegen.File {
 			{Path: "net/http"},
 			{Path: "strconv"},
 			{Path: "strings"},
-			{Path: "sync"},
 			{Path: "time"},
 			{Path: "github.com/gorilla/websocket"},
 			codegen.GoaImport(""),
@@ -62,8 +66,6 @@ func client(genpkg string, svc *expr.HTTPServiceExpr) *codegen.File {
 		}
 	}
 
-	sections = append(sections, clientStructWSSections(data)...)
-
 	sections = append(sections, &codegen.SectionTemplate{
 		Name:    "client-init",
 		Source:  clientInitT,
@@ -73,20 +75,19 @@ func client(genpkg string, svc *expr.HTTPServiceExpr) *codegen.File {
 
 	for _, e := range data.Endpoints {
 		sections = append(sections, &codegen.SectionTemplate{
-			Name:   "client-endpoint-init",
-			Source: endpointInitT,
-			Data:   e,
+			Name:    "client-endpoint-init",
+			Source:  endpointInitT,
+			Data:    e,
+			FuncMap: map[string]interface{}{"isWebSocketEndpoint": isWebSocketEndpoint},
 		})
 	}
 
-	sections = append(sections, clientWSSections(data)...)
-
 	return &codegen.File{Path: path, SectionTemplates: sections}
 }
 
-// clientEncodeDecode returns the file containing the HTTP client encoding and
-// decoding logic.
-func clientEncodeDecode(genpkg string, svc *expr.HTTPServiceExpr) *codegen.File {
+// clientEncodeDecodeFile returns the file containing the HTTP client encoding
+// and decoding logic.
+func clientEncodeDecodeFile(genpkg string, svc *expr.HTTPServiceExpr) *codegen.File {
 	data := HTTPServices.Get(svc.Name())
 	svcName := codegen.SnakeCase(data.Service.VarName)
 	path := filepath.Join(codegen.Gendir, "http", svcName, "client", "encode_decode.go")
@@ -101,6 +102,7 @@ func clientEncodeDecode(genpkg string, svc *expr.HTTPServiceExpr) *codegen.File
 			{Path: "mime/multipart"},
 			{Path: "net/http"},
 			{Path: "net/url"},
+			{Path: "os"},
 			{Path: "strconv"},
 			{Path: "strings"},
 			{Path: "unicode/utf8"},
@@ -117,7 +119,7 @@ func clientEncodeDecode(genpkg string, svc *expr.HTTPServiceExpr) *codegen.File
 			Source: requestBuilderT,
 			Data:   e,
 		})
-		if e.RequestEncoder != "" {
+		if e.RequestEncoder != "" && e.Payload.Ref != "" {
 			sections = append(sections, &codegen.SectionTemplate{
 				Name:   "request-encoder",
 				Source: requestEncoderT,
@@ -151,6 +153,13 @@ func clientEncodeDecode(genpkg string, svc *expr.HTTPServiceExpr) *codegen.File
 				},
 			})
 		}
+		if e.Method.SkipRequestBodyEncodeDecode {
+			sections = append(sections, &codegen.SectionTemplate{
+				Name:   "buid-stream-request",
+				Source: buildStreamRequestT,
+				Data:   e,
+			})
+		}
 	}
 	for _, h := range data.ClientTransformHelpers {
 		sections = append(sections, &codegen.SectionTemplate{
@@ -258,7 +267,7 @@ func New{{ .ClientStruct }}(
 const endpointInitT = `{{ printf "%s returns an endpoint that makes HTTP requests to the %s service %s server." .EndpointInit .ServiceName .Method.Name | comment }}
 func (c *{{ .ClientStruct }}) {{ .EndpointInit }}({{ if .MultipartRequestEncoder }}{{ .MultipartRequestEncoder.VarName }} {{ .MultipartRequestEncoder.FuncName }}{{ end }}) goa.Endpoint {
 	var (
-		{{- if and .ClientStream .RequestEncoder }}
+		{{- if and .ClientWebSocket .RequestEncoder }}
 		encodeRequest  = {{ .RequestEncoder }}({{ if .MultipartRequestEncoder }}{{ .MultipartRequestEncoder.InitName }}({{ .MultipartRequestEncoder.VarName }}){{ else }}c.encoder{{ end }})
 		{{- else }}
 			{{- if .RequestEncoder }}
@@ -268,7 +277,7 @@ func (c *{{ .ClientStruct }}) {{ .EndpointInit }}({{ if .MultipartRequestEncoder
 		decodeResponse = {{ .ResponseDecoder }}(c.decoder, c.RestoreResponseBody)
 	)
 	return func(ctx context.Context, v interface{}) (interface{}, error) {
-		req, err := c.{{ .RequestInit.Name }}(ctx, {{ range .RequestInit.ClientArgs }}{{ .Ref }}{{ end }})
+		req, err := c.{{ .RequestInit.Name }}(ctx, {{ range .RequestInit.ClientArgs }}{{ .Ref }}, {{ end }})
 		if err != nil {
 			return nil, err
 		}
@@ -279,11 +288,9 @@ func (c *{{ .ClientStruct }}) {{ .EndpointInit }}({{ if .MultipartRequestEncoder
 		}
 	{{- end }}
 
-	{{- if .ClientStream }}
+	{{- if isWebSocketEndpoint . }}
 		var cancel context.CancelFunc
-		{
-			ctx, cancel = context.WithCancel(ctx)
-		}
+		ctx, cancel = context.WithCancel(ctx)
 		conn, resp, err := c.dialer.DialContext(ctx, req.URL.String(), req.Header)
 		if err != nil {
 			if resp != nil {
@@ -294,7 +301,7 @@ func (c *{{ .ClientStruct }}) {{ .EndpointInit }}({{ if .MultipartRequestEncoder
 		if c.configurer.{{ .Method.VarName }}Fn != nil {
 			conn = c.configurer.{{ .Method.VarName }}Fn(conn, cancel)
 		}
-	{{- if eq .ClientStream.SendName "" }}
+		{{- if eq .ClientWebSocket.SendName "" }}
 		go func() {
 			<-ctx.Done()
 			conn.WriteControl(
@@ -304,8 +311,8 @@ func (c *{{ .ClientStruct }}) {{ .EndpointInit }}({{ if .MultipartRequestEncoder
 			)
 			conn.Close()
 		}()
-	{{- end }}
-		stream := &{{ .ClientStream.VarName }}{conn: conn}
+		{{- end }}
+		stream := &{{ .ClientWebSocket.VarName }}{conn: conn}
 		{{- if .Method.ViewedResult }}
 			{{- if not .Method.ViewedResult.ViewName }}
 		view := resp.Header.Get("goa-view")
@@ -315,11 +322,19 @@ func (c *{{ .ClientStruct }}) {{ .EndpointInit }}({{ if .MultipartRequestEncoder
 		return stream, nil
 	{{- else }}
 		resp, err := c.{{ .Method.VarName }}Doer.Do(req)
-
 		if err != nil {
 			return nil, goahttp.ErrRequestError("{{ .ServiceName }}", "{{ .Method.Name }}", err)
 		}
+		{{- if .Method.SkipResponseBodyEncodeDecode }}
+		{{ if .Result.Ref }}res{{ else }}_{{ end }}, err := decodeResponse(resp)
+		if err != nil {
+			resp.Body.Close()
+			return nil, goahttp.ErrDecodingError("{{ .ServiceName }}", "{{ .Method.Name }}", err)
+		}
+		return &{{ .ServicePkgName }}.{{ .Method.ResponseStruct }}{ {{ if .Result.Ref }}Result: res.({{ .Result.Ref }}), {{ end }}Body: resp.Body}, nil
+		{{- else }}
 		return decodeResponse(resp)
+		{{- end }}
 	{{- end }}
 	}
 }
@@ -327,7 +342,7 @@ func (c *{{ .ClientStruct }}) {{ .EndpointInit }}({{ if .MultipartRequestEncoder
 
 // input: EndpointData
 const requestBuilderT = `{{ comment .RequestInit.Description }}
-func (c *{{ .ClientStruct }}) {{ .RequestInit.Name }}(ctx context.Context, {{ range .RequestInit.ClientArgs }}{{ .Name }} {{ .TypeRef }}{{ end }}) (*http.Request, error) {
+func (c *{{ .ClientStruct }}) {{ .RequestInit.Name }}(ctx context.Context, {{ range .RequestInit.ClientArgs }}{{ .Name }} {{ .TypeRef }},{{ end }}) (*http.Request, error) {
 	{{- .RequestInit.ClientCode }}
 }
 `
@@ -336,10 +351,18 @@ func (c *{{ .ClientStruct }}) {{ .RequestInit.Name }}(ctx context.Context, {{ ra
 const requestEncoderT = `{{ printf "%s returns an encoder for requests sent to the %s %s server." .RequestEncoder .ServiceName .Method.Name | comment }}
 func {{ .RequestEncoder }}(encoder func(*http.Request) goahttp.Encoder) func(*http.Request, interface{}) error {
 	return func(req *http.Request, v interface{}) error {
+		{{- if .Method.SkipRequestBodyEncodeDecode }}
+		data, ok := v.(*{{ .ServicePkgName }}.{{ .Method.RequestStruct }})
+		if !ok {
+			return goahttp.ErrInvalidType("{{ .ServiceName }}", "{{ .Method.Name }}", "*{{ .ServicePkgName}}.{{ .Method.RequestStruct }}", v)
+		}
+		p := data.Payload
+		{{- else }}
 		p, ok := v.({{ .Payload.Ref }})
 		if !ok {
 			return goahttp.ErrInvalidType("{{ .ServiceName }}", "{{ .Method.Name }}", "{{ .Payload.Ref }}", v)
 		}
+		{{- end }}
 	{{- range .Payload.Request.Headers }}
 		{{- if .FieldName }}
 			{{- if .FieldPointer }}
@@ -533,9 +556,11 @@ func {{ .ResponseDecoder }}(decoder func(*http.Response) goahttp.Decoder, restor
 			defer func() {
 				resp.Body = ioutil.NopCloser(bytes.NewBuffer(b))
 			}()
-		} else {
+		}
+		{{- if not .Method.SkipResponseBodyEncodeDecode }} else {
 			defer resp.Body.Close()
 		}
+		{{- end }}
 		switch resp.StatusCode {
 	{{- range .Result.Responses }}
 		case {{ .StatusCode }}:
@@ -543,21 +568,21 @@ func {{ .ResponseDecoder }}(decoder func(*http.Response) goahttp.Decoder, restor
 		{{- if .ResultInit }}
 			{{- if .ViewedResult }}
 			p := {{ .ResultInit.Name }}({{ range .ResultInit.ClientArgs }}{{ .Ref }},{{ end }})
-			{{- if .TagName }}
+				{{- if .TagName }}
 				tmp := {{ printf "%q" .TagValue }}
 				p.{{ .TagName }} = &tmp
-			{{- end }}
+				{{- end }}
 				{{- if $.Method.ViewedResult.ViewName }}
 			view := {{ printf "%q" $.Method.ViewedResult.ViewName }}
 				{{- else }}
 			view := resp.Header.Get("goa-view")
 				{{- end }}
 			vres := {{ if not $.Method.ViewedResult.IsCollection }}&{{ end }}{{ $.Method.ViewedResult.ViewsPkg}}.{{ $.Method.ViewedResult.VarName }}{Projected: p, View: view}
-			{{- if .ClientBody }}
+				{{- if .ClientBody }}
 				if err = {{ $.Method.ViewedResult.ViewsPkg}}.Validate{{ $.Method.Result }}(vres); err != nil {
 					return nil, goahttp.ErrValidationError("{{ $.ServiceName }}", "{{ $.Method.Name }}", err)
 				}
-			{{- end }}
+				{{- end }}
 			res := {{ $.ServicePkgName }}.{{ $.Method.ViewedResult.ResultInit.Name }}(vres)
 			{{- else }}
 			res := {{ .ResultInit.Name }}({{ range .ResultInit.ClientArgs }}{{ .Ref }},{{ end }})
@@ -763,3 +788,19 @@ func {{ .InitName }}(encoderFn {{ .FuncName }}) func(r *http.Request) goahttp.En
 	}
 }
 `
+
+// input: streamRequestData
+const buildStreamRequestT = `// {{ printf "%s creates a streaming endpoint request payload from the method payload and the path to the file to be streamed" .BuildStreamPayload | comment }}
+func {{ .BuildStreamPayload }}({{ if .Payload.Ref }}payload interface{}, {{ end }}fpath string) (*{{ .ServicePkgName }}.{{ .Method.RequestStruct }}, error) {
+	f, err := os.Open(fpath)
+	if err != nil {
+		return nil, err
+	}
+	return &{{ .ServicePkgName }}.{{ .Method.RequestStruct }}{
+		{{- if .Payload.Ref }}
+		Payload: payload.({{ .Payload.Ref }}),
+		{{- end }}
+		Body: f,
+	}, nil
+}
+`
diff --git a/http/codegen/client_cli.go b/http/codegen/client_cli.go
index 6762ec0f..8b115288 100644
--- a/http/codegen/client_cli.go
+++ b/http/codegen/client_cli.go
@@ -21,10 +21,19 @@ type commandData struct {
 // commandData wraps the common SubcommandData and adds HTTP-specific fields.
 type subcommandData struct {
 	*cli.SubcommandData
-	// MultipartFuncName is the function name used to render a multipart request encoder.
+	// MultipartFuncName is the name of the function used to render a multipart
+	// request encoder.
 	MultipartFuncName string
-	// MultipartFuncName is the variable name used to render a multipart request encoder.
+	// MultipartFuncName is the name of the variabl used to render a multipart
+	// request encoder.
 	MultipartVarName string
+	// StreamFlag is the flag used to identify the file to be streamed when
+	// the endpoint uses SkipRequestBodyEncodeDecode.
+	StreamFlag *cli.FlagData
+	// BuildStreamPayload is the name of the generated function that builds the
+	// request data structure that wraps the payload and the file stream for
+	// endpoints that use SkipRequestBodyEncodeDecode.
+	BuildStreamPayload string
 }
 
 // ClientCLIFiles returns the client HTTP CLI support file.
@@ -76,6 +85,10 @@ func buildSubcommandData(sd *ServiceData, e *EndpointData) *subcommandData {
 		sub.MultipartVarName = e.MultipartRequestEncoder.VarName
 		sub.MultipartFuncName = e.MultipartRequestEncoder.FuncName
 	}
+	if e.Method.SkipRequestBodyEncodeDecode {
+		sub.StreamFlag = streamFlag(sd.Service.Name, e.Method.Name)
+		sub.BuildStreamPayload = e.BuildStreamPayload
+	}
 	return sub
 }
 
@@ -127,9 +140,7 @@ func endpointParser(genpkg string, root *expr.RootExpr, svr *expr.ServerExpr, da
 				cli.FlagsCode(cliData),
 				data,
 			},
-			FuncMap: map[string]interface{}{
-				"streamingCmdExists": streamingCmdExists,
-			},
+			FuncMap: map[string]interface{}{"streamingCmdExists": streamingCmdExists},
 		},
 	}
 	for _, cmd := range cliData {
@@ -181,9 +192,12 @@ func buildFlags(svc *ServiceData, e *EndpointData) ([]*cli.FlagData, *cli.BuildF
 			args = append(args, e.Payload.Request.PayloadInit.CLIArgs...)
 			flags, buildFunction = makeFlags(e, args)
 		} else if e.Payload.Ref != "" {
-			flags = append(flags, cli.NewFlagData(svcn, en, "p", e.Method.PayloadRef, e.Method.PayloadDesc, true, e.Method.PayloadEx))
+			flags = append(flags, cli.NewFlagData(svcn, en, "p", e.Method.PayloadRef, e.Method.PayloadDesc, true, e.Method.PayloadEx, e.Method.PayloadDefault))
 		}
 	}
+	if e.Method.SkipRequestBodyEncodeDecode {
+		flags = append(flags, streamFlag(svcn, en))
+	}
 
 	return flags, buildFunction
 }
@@ -204,7 +218,7 @@ func makeFlags(e *EndpointData, args []*InitArgData) ([]*cli.FlagData, *cli.Buil
 			FieldPointer: arg.FieldPointer,
 		}
 
-		f := cli.NewFlagData(e.ServiceName, e.Method.Name, arg.Name, arg.TypeName, arg.Description, arg.Required, arg.Example)
+		f := cli.NewFlagData(e.ServiceName, e.Method.Name, arg.Name, arg.TypeName, arg.Description, arg.Required, arg.Example, arg.DefaultValue)
 		flags[i] = f
 		params[i] = f.FullName
 		if arg.FieldName == "" && arg.Name != "body" {
@@ -248,6 +262,12 @@ func makeFlags(e *EndpointData, args []*InitArgData) ([]*cli.FlagData, *cli.Buil
 	}
 }
 
+// streamFlag returns the flag used to specify the upload file for endpoints
+// that use SkipRequestBodyEncodeDecode.
+func streamFlag(svcn, en string) *cli.FlagData {
+	return cli.NewFlagData(svcn, en, "stream", "string", "path to file containing the streamed request body", true, "goa.png", nil)
+}
+
 // streamingCmdExists returns true if at least one command in the list of commands
 // uses stream for sending payload/result.
 func streamingCmdExists(data []*commandData) bool {
@@ -305,6 +325,15 @@ func ParseEndpoint(
 			{{- else }}
 				data = nil
 			{{- end }}
+			{{- if .StreamFlag }}
+				{{- if .BuildFunction }}
+				if err == nil {
+				{{- end }}
+					data, err = {{ $pkgName }}.{{ .BuildStreamPayload }}({{ if or .BuildFunction .Conversion }}data, {{ end }}*{{ .StreamFlag.FullName }}Flag)
+				{{- if .BuildFunction }}
+				}
+				{{- end }}
+			{{- end }}
 		{{- end }}
 			}
 	{{- end }}
diff --git a/http/codegen/client_types.go b/http/codegen/client_types.go
index 29a0f33b..12e6fc4f 100644
--- a/http/codegen/client_types.go
+++ b/http/codegen/client_types.go
@@ -86,8 +86,8 @@ func clientType(genpkg string, svc *expr.HTTPServiceExpr, seen map[string]struct
 				validatedTypes = append(validatedTypes, data)
 			}
 		}
-		if adata.ClientStream != nil {
-			if data := adata.ClientStream.Payload; data != nil {
+		if adata.ClientWebSocket != nil {
+			if data := adata.ClientWebSocket.Payload; data != nil {
 				if _, ok := seen[data.Name]; ok {
 					continue
 				}
diff --git a/http/codegen/server.go b/http/codegen/server.go
index 45214eea..58598866 100644
--- a/http/codegen/server.go
+++ b/http/codegen/server.go
@@ -11,16 +11,21 @@ import (
 	"goa.design/goa/v3/expr"
 )
 
-// ServerFiles returns all the server HTTP transport files.
+// ServerFiles returns the generated HTTP server files.
 func ServerFiles(genpkg string, root *expr.RootExpr) []*codegen.File {
-	fw := make([]*codegen.File, 2*len(root.API.HTTP.Services))
-	for i, svc := range root.API.HTTP.Services {
-		fw[i] = serverFile(genpkg, svc)
+	var files []*codegen.File
+	for _, svc := range root.API.HTTP.Services {
+		files = append(files, serverFile(genpkg, svc))
+		if f := websocketServerFile(genpkg, svc); f != nil {
+			files = append(files, f)
+		}
 	}
-	for i, r := range root.API.HTTP.Services {
-		fw[i+len(root.API.HTTP.Services)] = serverEncodeDecode(genpkg, r)
+	for _, svc := range root.API.HTTP.Services {
+		if f := serverEncodeDecodeFile(genpkg, svc); f != nil {
+			files = append(files, f)
+		}
 	}
-	return fw
+	return files
 }
 
 // server returns the file implementing the HTTP server.
@@ -30,9 +35,11 @@ func serverFile(genpkg string, svc *expr.HTTPServiceExpr) *codegen.File {
 	path := filepath.Join(codegen.Gendir, "http", svcName, "server", "server.go")
 	title := fmt.Sprintf("%s HTTP server", svc.Name())
 	funcs := map[string]interface{}{
-		"join":             func(ss []string, s string) string { return strings.Join(ss, s) },
-		"hasWebSocket":     hasWebSocket,
-		"viewedServerBody": viewedServerBody,
+		"join":                func(ss []string, s string) string { return strings.Join(ss, s) },
+		"hasWebSocket":        hasWebSocket,
+		"isWebSocketEndpoint": isWebSocketEndpoint,
+		"viewedServerBody":    viewedServerBody,
+		"mustDecodeRequest":   mustDecodeRequest,
 	}
 	sections := []*codegen.SectionTemplate{
 		codegen.Header(title, "server", []*codegen.ImportSpec{
@@ -43,8 +50,6 @@ func serverFile(genpkg string, svc *expr.HTTPServiceExpr) *codegen.File {
 			{Path: "net/http"},
 			{Path: "path"},
 			{Path: "strings"},
-			{Path: "sync"},
-			{Path: "time"},
 			{Path: "github.com/gorilla/websocket"},
 			codegen.GoaImport(""),
 			codegen.GoaNamedImport("http", "goahttp"),
@@ -66,8 +71,6 @@ func serverFile(genpkg string, svc *expr.HTTPServiceExpr) *codegen.File {
 		}
 	}
 
-	sections = append(sections, serverStructWSSections(data)...)
-
 	sections = append(sections, &codegen.SectionTemplate{Name: "server-init", Source: serverInitT, Data: data, FuncMap: funcs})
 	sections = append(sections, &codegen.SectionTemplate{Name: "server-service", Source: serverServiceT, Data: data})
 	sections = append(sections, &codegen.SectionTemplate{Name: "server-use", Source: serverUseT, Data: data})
@@ -75,20 +78,18 @@ func serverFile(genpkg string, svc *expr.HTTPServiceExpr) *codegen.File {
 
 	for _, e := range data.Endpoints {
 		sections = append(sections, &codegen.SectionTemplate{Name: "server-handler", Source: serverHandlerT, Data: e})
-		sections = append(sections, &codegen.SectionTemplate{Name: "server-handler-init", Source: serverHandlerInitT, Data: e})
+		sections = append(sections, &codegen.SectionTemplate{Name: "server-handler-init", Source: serverHandlerInitT, FuncMap: funcs, Data: e})
 	}
 	for _, s := range data.FileServers {
 		sections = append(sections, &codegen.SectionTemplate{Name: "server-files", Source: fileServerT, FuncMap: funcs, Data: s})
 	}
 
-	sections = append(sections, serverWSSections(data)...)
-
 	return &codegen.File{Path: path, SectionTemplates: sections}
 }
 
-// serverEncodeDecode returns the file defining the HTTP server encoding and
+// serverEncodeDecodeFile returns the file defining the HTTP server encoding and
 // decoding logic.
-func serverEncodeDecode(genpkg string, svc *expr.HTTPServiceExpr) *codegen.File {
+func serverEncodeDecodeFile(genpkg string, svc *expr.HTTPServiceExpr) *codegen.File {
 	data := HTTPServices.Get(svc.Name())
 	svcName := codegen.SnakeCase(data.Service.VarName)
 	path := filepath.Join(codegen.Gendir, "http", svcName, "server", "encode_decode.go")
@@ -112,7 +113,7 @@ func serverEncodeDecode(genpkg string, svc *expr.HTTPServiceExpr) *codegen.File
 	}
 
 	for _, e := range data.Endpoints {
-		if e.ServerStream == nil {
+		if !isWebSocketEndpoint(e) {
 			sections = append(sections, &codegen.SectionTemplate{
 				Name:    "response-encoder",
 				FuncMap: transTmplFuncs(svc),
@@ -120,7 +121,7 @@ func serverEncodeDecode(genpkg string, svc *expr.HTTPServiceExpr) *codegen.File
 				Data:    e,
 			})
 		}
-		if e.Payload.Ref != "" {
+		if mustDecodeRequest(e) {
 			fm := transTmplFuncs(svc)
 			fm["mapQueryDecodeData"] = mapQueryDecodeData
 			sections = append(sections, &codegen.SectionTemplate{
@@ -140,7 +141,6 @@ func serverEncodeDecode(genpkg string, svc *expr.HTTPServiceExpr) *codegen.File
 				Data:    e.MultipartRequestDecoder,
 			})
 		}
-
 		if len(e.Errors) > 0 {
 			sections = append(sections, &codegen.SectionTemplate{
 				Name:    "error-encoder",
@@ -158,6 +158,12 @@ func serverEncodeDecode(genpkg string, svc *expr.HTTPServiceExpr) *codegen.File
 		})
 	}
 
+	// If all endpoints use skip encoding and decoding of both payloads and
+	// results and define no error then this file is irrelevant.
+	if len(sections) == 1 {
+		return nil
+	}
+
 	return &codegen.File{Path: path, SectionTemplates: sections}
 }
 
@@ -173,6 +179,11 @@ func transTmplFuncs(s *expr.HTTPServiceExpr) map[string]interface{} {
 	}
 }
 
+// mustDecodeRequest returns true if the Payload type is not empty.
+func mustDecodeRequest(e *EndpointData) bool {
+	return e.Payload.Ref != ""
+}
+
 // conversionData creates a template context suitable for executing the
 // "type_conversion" template.
 func conversionData(varName, name string, dt expr.DataType) map[string]interface{} {
@@ -300,7 +311,7 @@ func {{ .ServerInit }}(
 			{{- end }}
 		},
 		{{- range .Endpoints }}
-		{{ .Method.VarName }}: {{ .HandlerInit }}(e.{{ .Method.VarName }}, mux, {{ if .MultipartRequestDecoder }}{{ .MultipartRequestDecoder.InitName }}(mux, {{ .MultipartRequestDecoder.VarName }}){{ else }}decoder{{ end }}, encoder, errhandler, formatter{{ if .ServerStream }}, upgrader, configurer.{{ .Method.VarName }}Fn{{ end }}),
+		{{ .Method.VarName }}: {{ .HandlerInit }}(e.{{ .Method.VarName }}, mux, {{ if .MultipartRequestDecoder }}{{ .MultipartRequestDecoder.InitName }}(mux, {{ .MultipartRequestDecoder.VarName }}){{ else }}decoder{{ end }}, encoder, errhandler, formatter{{ if isWebSocketEndpoint . }}, upgrader, configurer.{{ .Method.VarName }}Fn{{ end }}),
 		{{- end }}
 	}
 }
@@ -387,20 +398,16 @@ func {{ .HandlerInit }}(
 	encoder func(context.Context, http.ResponseWriter) goahttp.Encoder,
 	errhandler func(context.Context, http.ResponseWriter, error),
 	formatter func(err error) goahttp.Statuser,
-	{{- if .ServerStream }}
+	{{- if isWebSocketEndpoint . }}
 	upgrader goahttp.Upgrader,
 	configurer goahttp.ConnConfigureFunc,
 	{{- end }}
 ) http.Handler {
 	var (
-		{{- if .ServerStream }}
-			{{- if .Payload.Ref }}
-		decodeRequest  = {{ .RequestDecoder }}(mux, decoder)
-			{{- end }}
-		{{- else }}
-			{{- if .Payload.Ref }}
+		{{- if mustDecodeRequest . }}
 		decodeRequest  = {{ .RequestDecoder }}(mux, decoder)
-			{{- end }}
+		{{- end }}
+		{{- if not (isWebSocketEndpoint .) }}
 		encodeResponse = {{ .ResponseEncoder }}(encoder)
 		{{- end }}
 		encodeError    = {{ if .Errors }}{{ .ErrorEncoder }}{{ else }}goahttp.ErrorEncoder{{ end }}(encoder, formatter)
@@ -410,7 +417,7 @@ func {{ .HandlerInit }}(
 		ctx = context.WithValue(ctx, goa.MethodKey, {{ printf "%q" .Method.Name }})
 		ctx = context.WithValue(ctx, goa.ServiceKey, {{ printf "%q" .ServiceName }})
 
-	{{- if .Payload.Ref }}
+	{{- if mustDecodeRequest . }}
 		payload, err := decodeRequest(r)
 		if err != nil {
 			if err := encodeError(ctx, w, err); err != nil {
@@ -421,14 +428,11 @@ func {{ .HandlerInit }}(
 	{{- else }}
 		var err error
 	{{- end }}
-
-	{{ if .ServerStream }}
+	{{- if isWebSocketEndpoint . }}
 		var cancel context.CancelFunc
-		{
-			ctx, cancel = context.WithCancel(ctx)
-		}
+		ctx, cancel = context.WithCancel(ctx)
 		v := &{{ .ServicePkgName }}.{{ .Method.ServerStream.EndpointStruct }}{
-			Stream: &{{ .ServerStream.VarName }}{
+			Stream: &{{ .ServerWebSocket.VarName }}{
 				upgrader: upgrader,
 				configurer: configurer,
 				cancel: cancel,
@@ -440,12 +444,14 @@ func {{ .HandlerInit }}(
 		{{- end }}
 		}
 		_, err = endpoint(ctx, v)
+	{{- else if .Method.SkipRequestBodyEncodeDecode }}
+		data := &{{ .ServicePkgName }}.{{ .Method.RequestStruct }}{ {{ if .Payload.Ref }}Payload: payload.({{ .Payload.Ref }}), {{ end }}Body: r.Body }
+		res, err := endpoint(ctx, data)
 	{{- else }}
 		res, err := endpoint(ctx, {{ if .Payload.Ref }}payload{{ else }}nil{{ end }})
 	{{- end }}
-
 		if err != nil {
-			{{- if .ServerStream }}
+			{{- if isWebSocketEndpoint . }}
 			if _, ok := err.(websocket.HandshakeError); ok {
 				return
 			}
@@ -455,9 +461,23 @@ func {{ .HandlerInit }}(
 			}
 			return
 		}
-	{{- if not .ServerStream }}
-		if err := encodeResponse(ctx, w, res); err != nil {
+	{{- if .Method.SkipResponseBodyEncodeDecode }}
+		o := res.(*{{ .ServicePkgName }}.{{ .Method.ResponseStruct }})
+		defer o.Body.Close()
+	{{- end }}
+	{{- if not (isWebSocketEndpoint .) }}
+		if err := encodeResponse(ctx, w, {{ if .Method.SkipResponseBodyEncodeDecode }}o.Result{{ else }}res{{ end }}); err != nil {
 			errhandler(ctx, w, err)
+			{{- if .Method.SkipResponseBodyEncodeDecode }}
+			return
+			{{- end }}
+		}
+	{{- end }}
+	{{- if .Method.SkipResponseBodyEncodeDecode }}
+		if _, err := io.Copy(w, o.Body); err != nil {
+			if err := encodeError(ctx, w, err); err != nil {
+				errhandler(ctx, w, err)
+			}
 		}
 	{{- end }}
 	})
diff --git a/http/codegen/server_types.go b/http/codegen/server_types.go
index d01a834a..e32a3990 100644
--- a/http/codegen/server_types.go
+++ b/http/codegen/server_types.go
@@ -80,11 +80,11 @@ func serverType(genpkg string, svc *expr.HTTPServiceExpr, seen map[string]struct
 				validatedTypes = append(validatedTypes, data)
 			}
 		}
-		if adata.ServerStream != nil {
-			if data := adata.ServerStream.Payload; data != nil {
+		if adata.ServerWebSocket != nil {
+			if data := adata.ServerWebSocket.Payload; data != nil {
 				if data.Def != "" {
 					sections = append(sections, &codegen.SectionTemplate{
-						Name:   "request-body-type-decl",
+						Name:   "request-stream-payload-type-decl",
 						Source: typeDeclT,
 						Data:   data,
 					})
@@ -178,8 +178,8 @@ func serverType(genpkg string, svc *expr.HTTPServiceExpr, seen map[string]struct
 				Data:   init,
 			})
 		}
-		if adata.ServerStream != nil && adata.ServerStream.Payload != nil {
-			if init := adata.ServerStream.Payload.Init; init != nil {
+		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,
diff --git a/http/codegen/service_data.go b/http/codegen/service_data.go
index 9861c816..cb019502 100644
--- a/http/codegen/service_data.go
+++ b/http/codegen/service_data.go
@@ -130,9 +130,9 @@ type (
 		// MultipartRequestDecoder indicates the request decoder for
 		// multipart content type.
 		MultipartRequestDecoder *MultipartData
-		// ServerStream holds the data to render the server struct which
+		// ServerWebSocket holds the data to render the server struct which
 		// implements the server stream interface.
-		ServerStream *StreamData
+		ServerWebSocket *WebSocketData
 
 		// client
 
@@ -150,9 +150,12 @@ type (
 		// MultipartRequestEncoder indicates the request encoder for
 		// multipart content type.
 		MultipartRequestEncoder *MultipartData
-		// ClientStream holds the data to render the client struct which
+		// ClientWebSocket holds the data to render the client struct which
 		// implements the client stream interface.
-		ClientStream *StreamData
+		ClientWebSocket *WebSocketData
+		// BuildStreamPayload is the name of the function used to create the
+		// payload for endpoints that use SkipRequestBodyEncodeDecode.
+		BuildStreamPayload string
 	}
 
 	// FileServerData lists the data needed to generate file servers.
@@ -539,9 +542,9 @@ type (
 		Payload *PayloadData
 	}
 
-	// StreamData contains the data needed to render struct type that
+	// WebSocketData contains the data needed to render struct type that
 	// implements the server and client stream interfaces.
-	StreamData struct {
+	WebSocketData struct {
 		// VarName is the name of the struct.
 		VarName string
 		// Type is type of the stream (server or client).
@@ -799,19 +802,19 @@ func (d ServicesData) analyze(hs *expr.HTTPServiceExpr) *ServiceData {
 				"Verb":         routes[0].Verb,
 				"IsStreaming":  a.MethodExpr.IsStreaming(),
 			}
+			if a.SkipRequestBodyEncodeDecode {
+				data["RequestStruct"] = svc.PkgName + "." + ep.RequestStruct
+			}
 			var buf bytes.Buffer
 			if err := requestInitTmpl.Execute(&buf, data); err != nil {
 				panic(err) // bug
 			}
+			clientArgs := []*InitArgData{{Name: "v", Ref: "v", TypeRef: "interface{}"}}
 			requestInit = &InitData{
 				Name:        name,
 				Description: fmt.Sprintf("%s instantiates a HTTP request object with method and path set to call the %q service %q endpoint", name, svc.Name, ep.Name),
 				ClientCode:  buf.String(),
-				ClientArgs: []*InitArgData{{
-					Name:    "v",
-					Ref:     "v",
-					TypeRef: "interface{}",
-				}},
+				ClientArgs:  clientArgs,
 			}
 		}
 
@@ -839,7 +842,9 @@ func (d ServicesData) analyze(hs *expr.HTTPServiceExpr) *ServiceData {
 			RequestEncoder:  requestEncoder,
 			ResponseDecoder: fmt.Sprintf("Decode%sResponse", ep.VarName),
 		}
-		buildStreamData(ad, a, rd)
+		if a.MethodExpr.IsStreaming() {
+			initWebSocketData(ad, a, rd)
+		}
 
 		if a.MultipartRequest {
 			ad.MultipartRequestDecoder = &MultipartData{
@@ -860,6 +865,10 @@ func (d ServicesData) analyze(hs *expr.HTTPServiceExpr) *ServiceData {
 			}
 		}
 
+		if a.SkipRequestBodyEncodeDecode {
+			ad.BuildStreamPayload = scope.Unique("Build" + codegen.Goify(ep.Name, true) + "StreamPayload")
+		}
+
 		rd.Endpoints = append(rd.Endpoints, ad)
 	}
 
@@ -1738,10 +1747,8 @@ func buildErrorsData(e *expr.HTTPEndpointExpr, sd *ServiceData) []*ErrorGroupDat
 	return vals
 }
 
-func buildStreamData(ed *EndpointData, e *expr.HTTPEndpointExpr, sd *ServiceData) {
-	if !e.MethodExpr.IsStreaming() {
-		return
-	}
+// initWebSocketData initializes the WebSocket related data in ed.
+func initWebSocketData(ed *EndpointData, e *expr.HTTPEndpointExpr, sd *ServiceData) {
 	var (
 		svrSendTypeName string
 		svrSendTypeRef  string
@@ -1851,7 +1858,7 @@ func buildStreamData(ed *EndpointData, e *expr.HTTPEndpointExpr, sd *ServiceData
 			cliSendDesc = fmt.Sprintf("%s streams instances of %q to the %q endpoint websocket connection.", md.ClientStream.SendName, svrRecvTypeName, md.Name)
 		}
 	}
-	ed.ServerStream = &StreamData{
+	ed.ServerWebSocket = &WebSocketData{
 		VarName:      md.ServerStream.VarName,
 		Interface:    fmt.Sprintf("%s.%s", svc.PkgName, md.ServerStream.Interface),
 		Endpoint:     ed,
@@ -1870,7 +1877,7 @@ func buildStreamData(ed *EndpointData, e *expr.HTTPEndpointExpr, sd *ServiceData
 		RecvTypeRef:  svrRecvTypeRef,
 		MustClose:    md.ServerStream.MustClose,
 	}
-	ed.ClientStream = &StreamData{
+	ed.ClientWebSocket = &WebSocketData{
 		VarName:      md.ClientStream.VarName,
 		Interface:    fmt.Sprintf("%s.%s", svc.PkgName, md.ClientStream.Interface),
 		Endpoint:     ed,
@@ -2583,19 +2590,31 @@ const (
 	// requestInitT is the template used to render the code of HTTP
 	// request constructors.
 	requestInitT = `
-{{- if .Args }}
+{{- if or .Args .RequestStruct }}
 	var (
 	{{- range .Args }}
-	{{ .Name }} {{ .TypeRef }}
+		{{ .Name }} {{ .TypeRef }}
+	{{- end }}
+	{{- if .RequestStruct }}
+		body io.Reader
 	{{- end }}
 	)
 {{- end }}
 {{- if and .PayloadRef .Args }}
 	{
+	{{- if .RequestStruct }}
+		rd, ok := v.(*{{ .RequestStruct }})
+		if !ok {
+			return nil, goahttp.ErrInvalidType("{{ .ServiceName }}", "{{ .EndpointName }}", "{{ .RequestStruct }}", v)
+		}
+		p := rd.Payload
+		body = rd.Body
+	{{- else }}
 		p, ok := v.({{ .PayloadRef }})
 		if !ok {
 			return nil, goahttp.ErrInvalidType("{{ .ServiceName }}", "{{ .EndpointName }}", "{{ .PayloadRef }}", v)
 		}
+	{{- end }}
 	{{- range .Args }}
 		{{- if .Pointer }}
 		if p{{ if $.HasFields }}.{{ .FieldName }}{{ end }} != nil {
@@ -2606,6 +2625,12 @@ const (
 		{{- end }}
 	{{- end }}
 	}
+{{- else if .RequestStruct }}
+		rd, ok := v.(*{{ .RequestStruct }})
+		if !ok {
+			return nil, goahttp.ErrInvalidType("{{ .ServiceName }}", "{{ .EndpointName }}", "{{ .RequestStruct }}", v)
+		}
+		body = rd.Body
 {{- end }}
 	{{- if .IsStreaming }}
 		scheme := c.scheme
@@ -2617,7 +2642,7 @@ const (
 		}
 	{{- end }}
 	u := &url.URL{Scheme: {{ if .IsStreaming }}scheme{{ else }}c.scheme{{ end }}, Host: c.host, Path: {{ .PathInit.Name }}({{ range .Args }}{{ .Ref }}, {{ end }})}
-	req, err := http.NewRequest("{{ .Verb }}", u.String(), nil)
+	req, err := http.NewRequest("{{ .Verb }}", u.String(), {{ if .RequestStruct }}body{{ else }}nil{{ end }})
 	if err != nil {
 		return nil, goahttp.ErrInvalidURL("{{ .ServiceName }}", "{{ .EndpointName }}", u.String(), err)
 	}
diff --git a/http/codegen/websocket.go b/http/codegen/websocket.go
index ade34770..39e5ffb0 100644
--- a/http/codegen/websocket.go
+++ b/http/codegen/websocket.go
@@ -1,28 +1,92 @@
 package codegen
 
 import (
+	"fmt"
+	"path/filepath"
+
 	"goa.design/goa/v3/codegen"
 	"goa.design/goa/v3/expr"
 )
 
+// websocketServerFile returns the file implementing the WebSocket server
+// streaming implementation if any.
+func websocketServerFile(genpkg string, svc *expr.HTTPServiceExpr) *codegen.File {
+	data := HTTPServices.Get(svc.Name())
+	if !hasWebSocket(data) {
+		return nil
+	}
+	svcName := codegen.SnakeCase(data.Service.VarName)
+	title := fmt.Sprintf("%s WebSocket server streaming", svc.Name())
+	sections := []*codegen.SectionTemplate{
+		codegen.Header(title, "server", []*codegen.ImportSpec{
+			{Path: "context"},
+			{Path: "io"},
+			{Path: "net/http"},
+			{Path: "sync"},
+			{Path: "time"},
+			{Path: "github.com/gorilla/websocket"},
+			codegen.GoaImport(""),
+			codegen.GoaNamedImport("http", "goahttp"),
+			{Path: genpkg + "/" + svcName, Name: data.Service.PkgName},
+		}),
+	}
+	sections = append(sections, serverStructWSSections(data)...)
+	sections = append(sections, serverWSSections(data)...)
+
+	return &codegen.File{
+		Path:             filepath.Join(codegen.Gendir, "http", svcName, "server", "websocket.go"),
+		SectionTemplates: sections,
+	}
+}
+
+// websocketClientFile returns the file implementing the WebSocket client
+// streaming implementation if any.
+func websocketClientFile(genpkg string, svc *expr.HTTPServiceExpr) *codegen.File {
+	data := HTTPServices.Get(svc.Name())
+	if !hasWebSocket(data) {
+		return nil
+	}
+	svcName := codegen.SnakeCase(data.Service.VarName)
+	title := fmt.Sprintf("%s WebSocket client streaming", svc.Name())
+	sections := []*codegen.SectionTemplate{
+		codegen.Header(title, "client", []*codegen.ImportSpec{
+			{Path: "context"},
+			{Path: "io"},
+			{Path: "net/http"},
+			{Path: "sync"},
+			{Path: "time"},
+			{Path: "github.com/gorilla/websocket"},
+			codegen.GoaImport(""),
+			codegen.GoaNamedImport("http", "goahttp"),
+			{Path: genpkg + "/" + svcName + "/" + "views", Name: data.Service.ViewsPkg},
+			{Path: genpkg + "/" + svcName, Name: data.Service.PkgName},
+		}),
+	}
+	sections = append(sections, clientStructWSSections(data)...)
+	sections = append(sections, clientWSSections(data)...)
+
+	return &codegen.File{
+		Path:             filepath.Join(codegen.Gendir, "http", svcName, "client", "websocket.go"),
+		SectionTemplates: sections,
+	}
+}
+
 // serverStructWSSections return section templates that generate WebSocket
 // related struct type definitions for the server.
 func serverStructWSSections(data *ServiceData) []*codegen.SectionTemplate {
 	var sections []*codegen.SectionTemplate
-	if hasWebSocket(data) {
-		sections = append(sections, &codegen.SectionTemplate{
-			Name:    "server-stream-conn-configurer-struct",
-			Source:  webSocketConnConfigurerStructT,
-			Data:    data,
-			FuncMap: map[string]interface{}{"isWebSocketEndpoint": isWebSocketEndpoint},
-		})
-	}
+	sections = append(sections, &codegen.SectionTemplate{
+		Name:    "server-websocket-conn-configurer-struct",
+		Source:  webSocketConnConfigurerStructT,
+		Data:    data,
+		FuncMap: map[string]interface{}{"isWebSocketEndpoint": isWebSocketEndpoint},
+	})
 	for _, e := range data.Endpoints {
-		if e.ServerStream != nil {
+		if e.ServerWebSocket != nil {
 			sections = append(sections, &codegen.SectionTemplate{
-				Name:   "server-stream-struct-type",
+				Name:   "server-websocket-struct-type",
 				Source: webSocketStructTypeT,
-				Data:   e.ServerStream,
+				Data:   e.ServerWebSocket,
 			})
 		}
 	}
@@ -34,49 +98,47 @@ func serverStructWSSections(data *ServiceData) []*codegen.SectionTemplate {
 // specific code for the given service.
 func serverWSSections(data *ServiceData) []*codegen.SectionTemplate {
 	var sections []*codegen.SectionTemplate
-	if hasWebSocket(data) {
-		sections = append(sections, &codegen.SectionTemplate{
-			Name:    "server-stream-conn-configurer-struct-init",
-			Source:  webSocketConnConfigurerStructInitT,
-			Data:    data,
-			FuncMap: map[string]interface{}{"isWebSocketEndpoint": isWebSocketEndpoint},
-		})
-	}
+	sections = append(sections, &codegen.SectionTemplate{
+		Name:    "server-websocket-conn-configurer-struct-init",
+		Source:  webSocketConnConfigurerStructInitT,
+		Data:    data,
+		FuncMap: map[string]interface{}{"isWebSocketEndpoint": isWebSocketEndpoint},
+	})
 	for _, e := range data.Endpoints {
-		if e.ServerStream != nil {
-			if e.ServerStream.SendTypeRef != "" {
+		if e.ServerWebSocket != nil {
+			if e.ServerWebSocket.SendTypeRef != "" {
 				sections = append(sections, &codegen.SectionTemplate{
-					Name:   "server-stream-send",
+					Name:   "server-websocket-send",
 					Source: webSocketSendT,
-					Data:   e.ServerStream,
+					Data:   e.ServerWebSocket,
 					FuncMap: map[string]interface{}{
 						"upgradeParams":    upgradeParams,
 						"viewedServerBody": viewedServerBody,
 					},
 				})
 			}
-			switch e.ServerStream.Kind {
+			switch e.ServerWebSocket.Kind {
 			case expr.ClientStreamKind, expr.BidirectionalStreamKind:
 				sections = append(sections, &codegen.SectionTemplate{
-					Name:    "server-stream-recv",
+					Name:    "server-websocket-recv",
 					Source:  webSocketRecvT,
-					Data:    e.ServerStream,
+					Data:    e.ServerWebSocket,
 					FuncMap: map[string]interface{}{"upgradeParams": upgradeParams},
 				})
 			}
-			if e.ServerStream.MustClose {
+			if e.ServerWebSocket.MustClose {
 				sections = append(sections, &codegen.SectionTemplate{
-					Name:    "server-stream-close",
+					Name:    "server-websocket-close",
 					Source:  webSocketCloseT,
-					Data:    e.ServerStream,
+					Data:    e.ServerWebSocket,
 					FuncMap: map[string]interface{}{"upgradeParams": upgradeParams},
 				})
 			}
 			if e.Method.ViewedResult != nil && e.Method.ViewedResult.ViewName == "" {
 				sections = append(sections, &codegen.SectionTemplate{
-					Name:   "server-stream-set-view",
+					Name:   "server-websocket-set-view",
 					Source: webSocketSetViewT,
-					Data:   e.ServerStream,
+					Data:   e.ServerWebSocket,
 				})
 			}
 		}
@@ -88,20 +150,18 @@ func serverWSSections(data *ServiceData) []*codegen.SectionTemplate {
 // related struct type definitions for the client.
 func clientStructWSSections(data *ServiceData) []*codegen.SectionTemplate {
 	var sections []*codegen.SectionTemplate
-	if hasWebSocket(data) {
-		sections = append(sections, &codegen.SectionTemplate{
-			Name:    "client-stream-conn-configurer-struct",
-			Source:  webSocketConnConfigurerStructT,
-			Data:    data,
-			FuncMap: map[string]interface{}{"isWebSocketEndpoint": isWebSocketEndpoint},
-		})
-	}
+	sections = append(sections, &codegen.SectionTemplate{
+		Name:    "client-websocket-conn-configurer-struct",
+		Source:  webSocketConnConfigurerStructT,
+		Data:    data,
+		FuncMap: map[string]interface{}{"isWebSocketEndpoint": isWebSocketEndpoint},
+	})
 	for _, e := range data.Endpoints {
-		if e.ClientStream != nil {
+		if e.ClientWebSocket != nil {
 			sections = append(sections, &codegen.SectionTemplate{
-				Name:   "client-stream-struct-type",
+				Name:   "client-websocket-struct-type",
 				Source: webSocketStructTypeT,
-				Data:   e.ClientStream,
+				Data:   e.ClientWebSocket,
 			})
 		}
 	}
@@ -112,49 +172,47 @@ func clientStructWSSections(data *ServiceData) []*codegen.SectionTemplate {
 // specific code for the given service.
 func clientWSSections(data *ServiceData) []*codegen.SectionTemplate {
 	var sections []*codegen.SectionTemplate
-	if hasWebSocket(data) {
-		sections = append(sections, &codegen.SectionTemplate{
-			Name:    "client-stream-conn-configurer-struct-init",
-			Source:  webSocketConnConfigurerStructInitT,
-			Data:    data,
-			FuncMap: map[string]interface{}{"isWebSocketEndpoint": isWebSocketEndpoint},
-		})
-	}
+	sections = append(sections, &codegen.SectionTemplate{
+		Name:    "client-websocket-conn-configurer-struct-init",
+		Source:  webSocketConnConfigurerStructInitT,
+		Data:    data,
+		FuncMap: map[string]interface{}{"isWebSocketEndpoint": isWebSocketEndpoint},
+	})
 	for _, e := range data.Endpoints {
-		if e.ClientStream != nil {
-			if e.ClientStream.RecvTypeRef != "" {
+		if e.ClientWebSocket != nil {
+			if e.ClientWebSocket.RecvTypeRef != "" {
 				sections = append(sections, &codegen.SectionTemplate{
-					Name:    "client-stream-recv",
+					Name:    "client-websocket-recv",
 					Source:  webSocketRecvT,
-					Data:    e.ClientStream,
+					Data:    e.ClientWebSocket,
 					FuncMap: map[string]interface{}{"upgradeParams": upgradeParams},
 				})
 			}
-			switch e.ClientStream.Kind {
+			switch e.ClientWebSocket.Kind {
 			case expr.ClientStreamKind, expr.BidirectionalStreamKind:
 				sections = append(sections, &codegen.SectionTemplate{
-					Name:   "client-stream-send",
+					Name:   "client-websocket-send",
 					Source: webSocketSendT,
-					Data:   e.ClientStream,
+					Data:   e.ClientWebSocket,
 					FuncMap: map[string]interface{}{
 						"upgradeParams":    upgradeParams,
 						"viewedServerBody": viewedServerBody,
 					},
 				})
 			}
-			if e.ClientStream.MustClose {
+			if e.ClientWebSocket.MustClose {
 				sections = append(sections, &codegen.SectionTemplate{
-					Name:    "client-stream-close",
+					Name:    "client-websocket-close",
 					Source:  webSocketCloseT,
-					Data:    e.ClientStream,
+					Data:    e.ClientWebSocket,
 					FuncMap: map[string]interface{}{"upgradeParams": upgradeParams},
 				})
 			}
 			if e.Method.ViewedResult != nil && e.Method.ViewedResult.ViewName == "" {
 				sections = append(sections, &codegen.SectionTemplate{
-					Name:   "client-stream-set-view",
+					Name:   "client-websocket-set-view",
 					Source: webSocketSetViewT,
-					Data:   e.ClientStream,
+					Data:   e.ClientWebSocket,
 				})
 			}
 		}
@@ -176,13 +234,13 @@ func hasWebSocket(sd *ServiceData) bool {
 // isWebSocketEndpoint returns true if the endpoint defines a streaming payload
 // or result.
 func isWebSocketEndpoint(ed *EndpointData) bool {
-	return ed.ServerStream != nil || ed.ClientStream != nil
+	return ed.ServerWebSocket != nil || ed.ClientWebSocket != nil
 }
 
 const (
 	// webSocketStructTypeT renders the server and client struct types that
 	// implements the client and server stream interfaces. The data to render
-	// input: StreamData
+	// input: WebSocketData
 	webSocketStructTypeT = `{{ printf "%s implements the %s interface." .VarName .Interface | comment }}
 type {{ .VarName }} struct {
 {{- if eq .Type "server" }}
@@ -240,7 +298,7 @@ func NewConnConfigurer(fn goahttp.ConnConfigureFunc) *ConnConfigurer {
 
 	// webSocketSendT renders the function implementing the Send method in
 	// stream interface.
-	// input: StreamData
+	// input: WebSocketData
 	webSocketSendT = `{{ comment .SendDesc }}
 func (s *{{ .VarName }}) {{ .SendName }}(v {{ .SendTypeRef }}) error {
 {{- if eq .Type "server" }}
@@ -299,7 +357,7 @@ func (s *{{ .VarName }}) {{ .SendName }}(v {{ .SendTypeRef }}) error {
 
 	// webSocketRecvT renders the function implementing the Recv method in
 	// stream interface.
-	// input: StreamData
+	// input: WebSocketData
 	webSocketRecvT = `{{ comment .RecvDesc }}
 func (s *{{ .VarName }}) {{ .RecvName }}() ({{ .RecvTypeRef }}, error) {
 	var (
@@ -414,7 +472,7 @@ func (s *{{ .VarName }}) {{ .RecvName }}() ({{ .RecvTypeRef }}, error) {
 
 	// webSocketCloseT renders the function implementing the Close method in
 	// stream interface.
-	// input: StreamData
+	// input: WebSocketData
 	webSocketCloseT = `{{ printf "Close closes the %q endpoint websocket connection." .Endpoint.Method.Name | comment }}
 func (s *{{ .VarName }}) Close() error {
 	var err error
@@ -441,7 +499,7 @@ func (s *{{ .VarName }}) Close() error {
 
 	// webSocketSetViewT renders the function implementing the SetView method in
 	// server stream interface.
-	// input: StreamData
+	// input: WebSocketData
 	webSocketSetViewT = `{{ printf "SetView sets the view to render the %s type before sending to the %q endpoint websocket connection." .SendTypeName .Endpoint.Method.Name | comment }}
 func (s *{{ .VarName }}) SetView(view string) {
 	s.view = view
diff --git a/http/encoding.go b/http/encoding.go
index 009dd897..57e63931 100644
--- a/http/encoding.go
+++ b/http/encoding.go
@@ -19,6 +19,7 @@ const (
 	// request Accept-Type header. The value may be used by encoders and
 	// decoders to implement a content type negotiation algorithm.
 	AcceptTypeKey contextKey = iota + 1
+
 	// ContentTypeKey is the context key used to store the value of the HTTP
 	// response Content-Type header when explicitly set in the DSL. The value
 	// may be used by encoders to set the header appropriately.
@@ -205,11 +206,12 @@ func ResponseDecoder(resp *http.Response) Decoder {
 }
 
 // ErrorEncoder returns an encoder that encodes errors returned by service
-// methods. The encoder checks whether the error is a goa ServiceError struct
-// and if so uses the error temporary and timeout fields to infer a proper HTTP
-// status code and marshals the error struct to the body using the provided
-// encoder. If the error is not a goa ServiceError struct then it is encoded
-// as a permanent internal server error.
+// methods. The default encoder checks whether the error is a goa ServiceError
+// struct and if so uses the error temporary and timeout fields to infer a
+// proper HTTP status code and marshals the error struct to the body using the
+// provided encoder. If the error is not a goa ServiceError struct then it is
+// encoded as a permanent internal server error. This behavior as well as the
+// shape of the response can be overridden by providing a non-nil formatter.
 func ErrorEncoder(encoder func(context.Context, http.ResponseWriter) Encoder, formatter func(err error) Statuser) func(context.Context, http.ResponseWriter, error) error {
 	return func(ctx context.Context, w http.ResponseWriter, err error) error {
 		enc := encoder(ctx, w)
@@ -263,9 +265,7 @@ type textEncoder struct {
 	ct string
 }
 
-func (e *textEncoder) Encode(v interface{}) error {
-	var err error
-
+func (e *textEncoder) Encode(v interface{}) (err error) {
 	switch c := v.(type) {
 	case string:
 		_, err = e.w.Write([]byte(c))
@@ -276,8 +276,7 @@ func (e *textEncoder) Encode(v interface{}) error {
 	default:
 		err = fmt.Errorf("can't encode %T as %s", c, e.ct)
 	}
-
-	return err
+	return
 }
 
 func newTextDecoder(r io.Reader, ct string) Decoder {
@@ -294,15 +293,13 @@ func (e *textDecoder) Decode(v interface{}) error {
 	if err != nil {
 		return err
 	}
-
 	switch c := v.(type) {
 	case *string:
 		*c = string(b)
 	case *[]byte:
 		*c = b
 	default:
-		err = fmt.Errorf("can't decode %s to %T", e.ct, c)
+		return fmt.Errorf("can't decode %s to %T", e.ct, c)
 	}
-
-	return err
+	return nil
 }


Test patch:
diff --git a/codegen/service/testdata/endpoint_code.go b/codegen/service/testdata/endpoint_code.go
index 8de23499..cf10833f 100644
--- a/codegen/service/testdata/endpoint_code.go
+++ b/codegen/service/testdata/endpoint_code.go
@@ -192,9 +192,8 @@ type Endpoints struct {
 	StreamingResultMethod goa.Endpoint
 }
 
-// StreamingResultMethodEndpointInput is the input type of
-// "StreamingResultMethod" endpoint that holds the method payload and the
-// server stream.
+// StreamingResultMethodEndpointInput holds both the payload and the server
+// stream of the "StreamingResultMethod" method.
 type StreamingResultMethodEndpointInput struct {
 	// Payload is the method payload.
 	Payload *AType
@@ -232,9 +231,8 @@ type Endpoints struct {
 	StreamingResultNoPayloadMethod goa.Endpoint
 }
 
-// StreamingResultNoPayloadMethodEndpointInput is the input type of
-// "StreamingResultNoPayloadMethod" endpoint that holds the method payload and
-// the server stream.
+// StreamingResultNoPayloadMethodEndpointInput holds both the payload and the
+// server stream of the "StreamingResultNoPayloadMethod" method.
 type StreamingResultNoPayloadMethodEndpointInput struct {
 	// Stream is the server stream used by the "StreamingResultNoPayloadMethod"
 	// method to send data.
@@ -271,9 +269,8 @@ type Endpoints struct {
 	StreamingResultWithViewsMethod goa.Endpoint
 }
 
-// StreamingResultWithViewsMethodEndpointInput is the input type of
-// "StreamingResultWithViewsMethod" endpoint that holds the method payload and
-// the server stream.
+// StreamingResultWithViewsMethodEndpointInput holds both the payload and the
+// server stream of the "StreamingResultWithViewsMethod" method.
 type StreamingResultWithViewsMethodEndpointInput struct {
 	// Payload is the method payload.
 	Payload string
@@ -312,9 +309,8 @@ type Endpoints struct {
 	StreamingPayloadMethod goa.Endpoint
 }
 
-// StreamingPayloadMethodEndpointInput is the input type of
-// "StreamingPayloadMethod" endpoint that holds the method payload and the
-// server stream.
+// StreamingPayloadMethodEndpointInput holds both the payload and the server
+// stream of the "StreamingPayloadMethod" method.
 type StreamingPayloadMethodEndpointInput struct {
 	// Payload is the method payload.
 	Payload *BType
@@ -352,9 +348,8 @@ type Endpoints struct {
 	StreamingPayloadNoPayloadMethod goa.Endpoint
 }
 
-// StreamingPayloadNoPayloadMethodEndpointInput is the input type of
-// "StreamingPayloadNoPayloadMethod" endpoint that holds the method payload and
-// the server stream.
+// StreamingPayloadNoPayloadMethodEndpointInput holds both the payload and the
+// server stream of the "StreamingPayloadNoPayloadMethod" method.
 type StreamingPayloadNoPayloadMethodEndpointInput struct {
 	// Stream is the server stream used by the "StreamingPayloadNoPayloadMethod"
 	// method to send data.
@@ -391,9 +386,8 @@ type Endpoints struct {
 	StreamingPayloadNoResultMethod goa.Endpoint
 }
 
-// StreamingPayloadNoResultMethodEndpointInput is the input type of
-// "StreamingPayloadNoResultMethod" endpoint that holds the method payload and
-// the server stream.
+// StreamingPayloadNoResultMethodEndpointInput holds both the payload and the
+// server stream of the "StreamingPayloadNoResultMethod" method.
 type StreamingPayloadNoResultMethodEndpointInput struct {
 	// Stream is the server stream used by the "StreamingPayloadNoResultMethod"
 	// method to send data.
@@ -430,9 +424,8 @@ type Endpoints struct {
 	BidirectionalStreamingMethod goa.Endpoint
 }
 
-// BidirectionalStreamingMethodEndpointInput is the input type of
-// "BidirectionalStreamingMethod" endpoint that holds the method payload and
-// the server stream.
+// BidirectionalStreamingMethodEndpointInput holds both the payload and the
+// server stream of the "BidirectionalStreamingMethod" method.
 type BidirectionalStreamingMethodEndpointInput struct {
 	// Payload is the method payload.
 	Payload *AType
@@ -472,9 +465,8 @@ type Endpoints struct {
 	BidirectionalStreamingNoPayloadMethod goa.Endpoint
 }
 
-// BidirectionalStreamingNoPayloadMethodEndpointInput is the input type of
-// "BidirectionalStreamingNoPayloadMethod" endpoint that holds the method
-// payload and the server stream.
+// BidirectionalStreamingNoPayloadMethodEndpointInput holds both the payload
+// and the server stream of the "BidirectionalStreamingNoPayloadMethod" method.
 type BidirectionalStreamingNoPayloadMethodEndpointInput struct {
 	// Stream is the server stream used by the
 	// "BidirectionalStreamingNoPayloadMethod" method to send data.
diff --git a/expr/grpc_endpoint_test.go b/expr/grpc_endpoint_test.go
index b4a258cf..4c3b115d 100644
--- a/expr/grpc_endpoint_test.go
+++ b/expr/grpc_endpoint_test.go
@@ -25,8 +25,8 @@ service "Service" gRPC endpoint "Method": Map element type is Any type which is
 		},
 		"endpoint-with-untagged-fields": {
 			DSL: testdata.GRPCEndpointWithUntaggedFields,
-			Errors: []string{`service "Service" gRPC endpoint "Method": attribute "req_not_field" does not have "rpc:tag" defined in the meta
-service "Service" gRPC endpoint "Method": attribute "resp_not_field" does not have "rpc:tag" defined in the meta`,
+			Errors: []string{`service "Service" gRPC endpoint "Method": attribute "req_not_field" does not have "rpc:tag" defined in the meta, use "Field" to define the attribute of a type used in a gRPC method
+service "Service" gRPC endpoint "Method": attribute "resp_not_field" does not have "rpc:tag" defined in the meta, use "Field" to define the attribute of a type used in a gRPC method`,
 			},
 		},
 		"endpoint-with-repeated-field-tags": {
diff --git a/expr/http_endpoint_test.go b/expr/http_endpoint_test.go
index 7b9e3a55..829c0d94 100644
--- a/expr/http_endpoint_test.go
+++ b/expr/http_endpoint_test.go
@@ -96,17 +96,15 @@ func TestHTTPEndpointPrepare(t *testing.T) {
 
 func TestHTTPEndpointValidation(t *testing.T) {
 	cases := map[string]struct {
-		DSL    func()
-		Errors []string
+		DSL   func()
+		Error string
 	}{
 		"endpoint-body-as-payload-prop": {
 			DSL: testdata.EndpointBodyAsPayloadProp,
 		},
 		"endpoint-body-as-missed-payload-prop": {
-			DSL: testdata.EndpointBodyAsMissedPayloadProp,
-			Errors: []string{
-				"Request type does not have an attribute named \"name\" in service \"Service\" HTTP endpoint \"Method\"",
-			},
+			DSL:   testdata.EndpointBodyAsMissedPayloadProp,
+			Error: `Request type does not have an attribute named "name" in service "Service" HTTP endpoint "Method"`,
 		},
 		"endpoint-body-extend-payload": {
 			DSL: testdata.EndpointBodyExtendPayload,
@@ -115,16 +113,12 @@ func TestHTTPEndpointValidation(t *testing.T) {
 			DSL: testdata.EndpointBodyAsUserType,
 		},
 		"endpoint-missing-token": {
-			DSL: testdata.EndpointMissingToken,
-			Errors: []string{
-				"service \"Service\" method \"Method\": payload of method \"Method\" of service \"Service\" does not define a JWT attribute, use Token to define one",
-			},
+			DSL:   testdata.EndpointMissingToken,
+			Error: `service "Service" method "Method": payload of method "Method" of service "Service" does not define a JWT attribute, use Token to define one`,
 		},
 		"endpoint-missing-token-payload": {
-			DSL: testdata.EndpointMissingTokenPayload,
-			Errors: []string{
-				"service \"Service\" method \"Method\": payload of method \"Method\" of service \"Service\" does not define a JWT attribute, use Token to define one",
-			},
+			DSL:   testdata.EndpointMissingTokenPayload,
+			Error: `service "Service" method "Method": payload of method "Method" of service "Service" does not define a JWT attribute, use Token to define one`,
 		},
 		"endpoint-missing-token-extend": {
 			DSL: testdata.EndpointExtendToken,
@@ -135,14 +129,34 @@ func TestHTTPEndpointValidation(t *testing.T) {
 		"endpoint-has-parent-and-other": {
 			DSL: testdata.EndpointHasParentAndOther,
 		},
+		"endpoint-has-skip-request-encode-and-payload-streaming": {
+			DSL:   testdata.EndpointHasSkipRequestEncodeAndPayloadStreaming,
+			Error: `service "Service" HTTP endpoint "Method": Endpoint cannot use SkipRequestBodyEncodeDecode when method defines a StreamingPayload.`,
+		},
+		"endpoint-has-skip-request-encode-and-result-streaming": {
+			DSL:   testdata.EndpointHasSkipRequestEncodeAndResultStreaming,
+			Error: `service "Service" HTTP endpoint "Method": Endpoint cannot use SkipRequestBodyEncodeDecode when method defines a StreamingResult. Use SkipResponseBodyEncodeDecode instead.`,
+		},
+		"endpoint-has-skip-response-encode-and-payload-streaming": {
+			DSL:   testdata.EndpointHasSkipResponseEncodeAndPayloadStreaming,
+			Error: `service "Service" HTTP endpoint "Method": Endpoint cannot use SkipResponseBodyEncodeDecode when method defines a StreamingPayload. Use SkipRequestBodyEncodeDecode instead.`,
+		},
+		"endpoint-has-skip-response-encode-and-result-streaming": {
+			DSL: testdata.EndpointHasSkipResponseEncodeAndResultStreaming,
+			Error: `service "Service" HTTP endpoint "Method": Endpoint cannot use SkipResponseBodyEncodeDecode when method defines a StreamingResult.
+service "Service" HTTP endpoint "Method": HTTP endpoint response body must be empty when using SkipResponseBodyEncodeDecode. Make sure to define Headers as needed.`,
+		},
+		"endpoint-has-skip-encode-and-grpc": {
+			DSL:   testdata.EndpointHasSkipEncodeAndGRPC,
+			Error: `service "Service" HTTP endpoint "Method": Endpoint cannot use SkipRequestBodyEncodeDecode and define a gRPC transport.`,
+		},
 	}
 	for name, c := range cases {
 		t.Run(name, func(t *testing.T) {
-			if c.Errors == nil || len(c.Errors) == 0 {
+			if c.Error == "" {
 				expr.RunDSL(t, c.DSL)
 			} else {
 				var errors []error
-
 				err := expr.RunInvalidDSL(t, c.DSL)
 				if err != nil {
 					if merr, ok := err.(eval.MultiError); ok {
@@ -153,14 +167,11 @@ func TestHTTPEndpointValidation(t *testing.T) {
 						errors = append(errors, err)
 					}
 				}
-
-				if len(c.Errors) != len(errors) {
-					t.Errorf("got %d, expected the number of error values to match %d\nerrors:\n%s", len(errors), len(c.Errors), err.Error())
+				if len(errors) > 1 || len(errors) == 0 {
+					t.Errorf("got %d errors, expected 1", len(errors))
 				} else {
-					for i, err := range errors {
-						if err.Error() != c.Errors[i] {
-							t.Errorf("got \t\t%q,\nexpected\t%q at index %d", err.Error(), c.Errors[i], i)
-						}
+					if errors[0].Error() != c.Error {
+						t.Errorf("got `%s`, expected `%s`", err.Error(), c.Error)
 					}
 				}
 			}
diff --git a/expr/http_response_test.go b/expr/http_response_test.go
index d0d52c22..f027d1ab 100644
--- a/expr/http_response_test.go
+++ b/expr/http_response_test.go
@@ -27,6 +27,7 @@ func TestHTTPResponseValidation(t *testing.T) {
 		{"not string or []byte", intResultResponseWithTextContentTypeDSL, `HTTP response of service "StringResultResponseWithHeaders" HTTP endpoint "Method": Result type must be String or Bytes when ContentType is 'text/plain'`},
 		{"missing header result attribute", missingHeaderResultAttributeDSL, `HTTP response of service "MissingHeaderResultAttribute" HTTP endpoint "Method": header "bar" has no equivalent attribute in result type, use notation 'attribute_name:header_name' to identify corresponding result type attribute.
 service "MissingHeaderResultAttribute" HTTP endpoint "Method": attribute "bar" used in HTTP headers must be a primitive type or an array of primitive types.`},
+		{"skip encode and gRPC", skipEncodeAndGRPCDSL, `service "SkipEncodeAndGRPC" HTTP endpoint "Method": Endpoint response cannot use SkipResponseBodyEncodeDecode and define a gRPC transport.`},
 	}
 	for _, c := range cases {
 		t.Run(c.Name, func(t *testing.T) {
@@ -228,3 +229,21 @@ var missingHeaderResultAttributeDSL = func() {
 		})
 	})
 }
+
+var skipEncodeAndGRPCDSL = func() {
+	Service("SkipEncodeAndGRPC", func() {
+		Method("Method", func() {
+			Result(func() {
+				Field(1, "foo")
+			})
+			HTTP(func() {
+				POST("/")
+				SkipResponseBodyEncodeDecode()
+				Response(func() {
+					Header("foo")
+				})
+			})
+			GRPC(func() {})
+		})
+	})
+}
diff --git a/expr/testdata/endpoint_dsls.go b/expr/testdata/endpoint_dsls.go
index df34fea9..56ce7fc3 100644
--- a/expr/testdata/endpoint_dsls.go
+++ b/expr/testdata/endpoint_dsls.go
@@ -345,6 +345,71 @@ var EndpointHasParentAndOther = func() {
 
 }
 
+var EndpointHasSkipRequestEncodeAndPayloadStreaming = func() {
+	Service("Service", func() {
+		Method("Method", func() {
+			StreamingPayload(String)
+			HTTP(func() {
+				GET("/")
+				SkipRequestBodyEncodeDecode()
+			})
+		})
+	})
+}
+
+var EndpointHasSkipRequestEncodeAndResultStreaming = func() {
+	Service("Service", func() {
+		Method("Method", func() {
+			StreamingResult(String)
+			HTTP(func() {
+				GET("/")
+				SkipRequestBodyEncodeDecode()
+			})
+		})
+	})
+}
+
+var EndpointHasSkipResponseEncodeAndPayloadStreaming = func() {
+	Service("Service", func() {
+		Method("Method", func() {
+			StreamingPayload(String)
+			HTTP(func() {
+				GET("/")
+				SkipResponseBodyEncodeDecode()
+			})
+		})
+	})
+}
+
+var EndpointHasSkipResponseEncodeAndResultStreaming = func() {
+	Service("Service", func() {
+		Method("Method", func() {
+			StreamingResult(String)
+			HTTP(func() {
+				GET("/")
+				SkipResponseBodyEncodeDecode()
+			})
+		})
+	})
+}
+
+var EndpointHasSkipEncodeAndGRPC = func() {
+	Service("Service", func() {
+		Method("Method", func() {
+			Payload(func() {
+				Field(1, "param", Int)
+				Field(2, "query", String)
+			})
+			HTTP(func() {
+				GET("/{param}")
+				Param("query")
+				SkipRequestBodyEncodeDecode()
+			})
+			GRPC(func() {})
+		})
+	})
+}
+
 var FinalizeEndpointBodyAsExtendedTypeDSL = func() {
 	var EntityData = Type("EntityData", func() {
 		Attribute("name", String)
diff --git a/http/codegen/client_init_test.go b/http/codegen/client_init_test.go
index 0c6bc58d..20ef16d5 100644
--- a/http/codegen/client_init_test.go
+++ b/http/codegen/client_init_test.go
@@ -13,17 +13,18 @@ func TestClientInit(t *testing.T) {
 		Name       string
 		DSL        func()
 		Code       string
+		FileCount  int
 		SectionNum int
 	}{
-		{"multiple endpoints", testdata.ServerMultiEndpointsDSL, testdata.MultipleEndpointsClientInitCode, 2},
-		{"streaming", testdata.StreamingResultDSL, testdata.StreamingClientInitCode, 4},
+		{"multiple endpoints", testdata.ServerMultiEndpointsDSL, testdata.MultipleEndpointsClientInitCode, 2, 2},
+		{"streaming", testdata.StreamingResultDSL, testdata.StreamingClientInitCode, 3, 2},
 	}
 	for _, c := range cases {
 		t.Run(c.Name, func(t *testing.T) {
 			RunHTTPDSL(t, c.DSL)
 			fs := ClientFiles("", expr.Root)
-			if len(fs) != 2 {
-				t.Fatalf("got %d files, expected two", len(fs))
+			if len(fs) != c.FileCount {
+				t.Fatalf("got %d files, expected %v", len(fs), c.FileCount)
 			}
 			sections := fs[0].SectionTemplates
 			if len(sections) < 3 {
diff --git a/http/codegen/server_init_test.go b/http/codegen/server_init_test.go
index 1ec18e57..6677daa0 100644
--- a/http/codegen/server_init_test.go
+++ b/http/codegen/server_init_test.go
@@ -14,21 +14,22 @@ func TestServerInit(t *testing.T) {
 		Name       string
 		DSL        func()
 		Code       string
+		FileCount  int
 		SectionNum int
 	}{
-		{"multiple endpoints", testdata.ServerMultiEndpointsDSL, testdata.ServerMultiEndpointsConstructorCode, 3},
-		{"multiple bases", testdata.ServerMultiBasesDSL, testdata.ServerMultiBasesConstructorCode, 3},
-		{"file server", testdata.ServerFileServerDSL, testdata.ServerFileServerConstructorCode, 3},
-		{"mixed", testdata.ServerMixedDSL, testdata.ServerMixedConstructorCode, 3},
-		{"multipart", testdata.ServerMultipartDSL, testdata.ServerMultipartConstructorCode, 4},
-		{"streaming", testdata.StreamingResultDSL, testdata.ServerStreamingConstructorCode, 5},
+		{"multiple endpoints", testdata.ServerMultiEndpointsDSL, testdata.ServerMultiEndpointsConstructorCode, 2, 3},
+		{"multiple bases", testdata.ServerMultiBasesDSL, testdata.ServerMultiBasesConstructorCode, 2, 3},
+		{"file server", testdata.ServerFileServerDSL, testdata.ServerFileServerConstructorCode, 1, 3},
+		{"mixed", testdata.ServerMixedDSL, testdata.ServerMixedConstructorCode, 2, 3},
+		{"multipart", testdata.ServerMultipartDSL, testdata.ServerMultipartConstructorCode, 2, 4},
+		{"streaming", testdata.StreamingResultDSL, testdata.ServerStreamingConstructorCode, 3, 3},
 	}
 	for _, c := range cases {
 		t.Run(c.Name, func(t *testing.T) {
 			RunHTTPDSL(t, c.DSL)
 			fs := ServerFiles(genpkg, expr.Root)
-			if len(fs) != 2 {
-				t.Fatalf("got %d files, expected two", len(fs))
+			if len(fs) != c.FileCount {
+				t.Fatalf("got %d files, expected %v", len(fs), c.FileCount)
 			}
 			sections := fs[0].SectionTemplates
 			if len(sections) < 6 {
diff --git a/http/codegen/server_mount_test.go b/http/codegen/server_mount_test.go
index ef6d8503..656ec395 100644
--- a/http/codegen/server_mount_test.go
+++ b/http/codegen/server_mount_test.go
@@ -16,37 +16,17 @@ func TestServerMount(t *testing.T) {
 		Code       string
 		SectionNum int
 	}{
-		{
-			Name:       "multiple files constructor",
-			DSL:        testdata.ServerMultipleFilesDSL,
-			Code:       testdata.ServerMultipleFilesConstructorCode,
-			SectionNum: 6,
-		},
-		{
-			Name:       "multiple files mounter",
-			DSL:        testdata.ServerMultipleFilesDSL,
-			Code:       testdata.ServerMultipleFilesMounterCode,
-			SectionNum: 9,
-		},
-		{
-			Name:       "multiple files constructor /w prefix path",
-			DSL:        testdata.ServerMultipleFilesWithPrefixPathDSL,
-			Code:       testdata.ServerMultipleFilesWithPrefixPathConstructorCode,
-			SectionNum: 6,
-		},
-		{
-			Name:       "multiple files mounter /w prefix path",
-			DSL:        testdata.ServerMultipleFilesWithPrefixPathDSL,
-			Code:       testdata.ServerMultipleFilesWithPrefixPathMounterCode,
-			SectionNum: 9,
-		},
+		{"multiple files constructor", testdata.ServerMultipleFilesDSL, testdata.ServerMultipleFilesConstructorCode, 6},
+		{"multiple files mounter", testdata.ServerMultipleFilesDSL, testdata.ServerMultipleFilesMounterCode, 9},
+		{"multiple files constructor /w prefix path", testdata.ServerMultipleFilesWithPrefixPathDSL, testdata.ServerMultipleFilesWithPrefixPathConstructorCode, 6},
+		{"multiple files mounter /w prefix path", testdata.ServerMultipleFilesWithPrefixPathDSL, testdata.ServerMultipleFilesWithPrefixPathMounterCode, 9},
 	}
 	for _, c := range cases {
 		t.Run(c.Name, func(t *testing.T) {
 			RunHTTPDSL(t, c.DSL)
 			fs := ServerFiles(genpkg, expr.Root)
-			if len(fs) != 2 {
-				t.Fatalf("got %d files, expected two", len(fs))
+			if len(fs) != 1 {
+				t.Fatalf("got %d files, expected 1", len(fs))
 			}
 			sections := fs[0].SectionTemplates
 			if len(sections) < 6 {
diff --git a/http/codegen/streaming_test.go b/http/codegen/streaming_test.go
index 77a5a0aa..c4ec44de 100644
--- a/http/codegen/streaming_test.go
+++ b/http/codegen/streaming_test.go
@@ -31,49 +31,49 @@ type (
 func TestServerStreaming(t *testing.T) {
 	cases := []*testCase{
 		{"mixed-endpoints", testdata.StreamingResultDSL, []*sectionExpectation{
-			{"server-stream-conn-configurer-struct", &testdata.MixedEndpointsConnConfigurerStructCode},
-			{"server-stream-conn-configurer-struct-init", &testdata.MixedEndpointsConnConfigurerInitCode},
+			{"server-websocket-conn-configurer-struct", &testdata.MixedEndpointsConnConfigurerStructCode},
+			{"server-websocket-conn-configurer-struct-init", &testdata.MixedEndpointsConnConfigurerInitCode},
 		}},
 
 		// streaming result
 		{"streaming-result", testdata.StreamingResultDSL, []*sectionExpectation{
 			{"server-handler-init", &testdata.StreamingResultServerHandlerInitCode},
-			{"server-stream-send", &testdata.StreamingResultServerStreamSendCode},
-			{"server-stream-close", &testdata.StreamingResultServerStreamCloseCode},
-			{"server-stream-set-view", nil},
+			{"server-websocket-send", &testdata.StreamingResultServerStreamSendCode},
+			{"server-websocket-close", &testdata.StreamingResultServerStreamCloseCode},
+			{"server-websocket-set-view", nil},
 		}},
 		{"streaming-result-with-views", testdata.StreamingResultWithViewsDSL, []*sectionExpectation{
-			{"server-stream-send", &testdata.StreamingResultWithViewsServerStreamSendCode},
-			{"server-stream-close", &testdata.StreamingResultWithViewsServerStreamCloseCode},
-			{"server-stream-set-view", &testdata.StreamingResultWithViewsServerStreamSetViewCode},
+			{"server-websocket-send", &testdata.StreamingResultWithViewsServerStreamSendCode},
+			{"server-websocket-close", &testdata.StreamingResultWithViewsServerStreamCloseCode},
+			{"server-websocket-set-view", &testdata.StreamingResultWithViewsServerStreamSetViewCode},
 		}},
 		{"streaming-result-with-explicit-view", testdata.StreamingResultWithExplicitViewDSL, []*sectionExpectation{
-			{"server-stream-send", &testdata.StreamingResultWithExplicitViewServerStreamSendCode},
-			{"server-stream-set-view", nil},
+			{"server-websocket-send", &testdata.StreamingResultWithExplicitViewServerStreamSendCode},
+			{"server-websocket-set-view", nil},
 		}},
 		{"streaming-result-collection-with-views", testdata.StreamingResultCollectionWithViewsDSL, []*sectionExpectation{
-			{"server-stream-send", &testdata.StreamingResultCollectionWithViewsServerStreamSendCode},
-			{"server-stream-set-view", &testdata.StreamingResultCollectionWithViewsServerStreamSetViewCode},
+			{"server-websocket-send", &testdata.StreamingResultCollectionWithViewsServerStreamSendCode},
+			{"server-websocket-set-view", &testdata.StreamingResultCollectionWithViewsServerStreamSetViewCode},
 		}},
 		{"streaming-result-collection-with-explicit-view", testdata.StreamingResultCollectionWithExplicitViewDSL, []*sectionExpectation{
-			{"server-stream-send", &testdata.StreamingResultCollectionWithExplicitViewServerStreamSendCode},
-			{"server-stream-set-view", nil},
+			{"server-websocket-send", &testdata.StreamingResultCollectionWithExplicitViewServerStreamSendCode},
+			{"server-websocket-set-view", nil},
 		}},
 		{"streaming-result-primitive", testdata.StreamingResultPrimitiveDSL, []*sectionExpectation{
-			{"server-stream-send", &testdata.StreamingResultPrimitiveServerStreamSendCode},
-			{"server-stream-set-view", nil},
+			{"server-websocket-send", &testdata.StreamingResultPrimitiveServerStreamSendCode},
+			{"server-websocket-set-view", nil},
 		}},
 		{"streaming-result-primitive-array", testdata.StreamingResultPrimitiveArrayDSL, []*sectionExpectation{
-			{"server-stream-send", &testdata.StreamingResultPrimitiveArrayServerStreamSendCode},
+			{"server-websocket-send", &testdata.StreamingResultPrimitiveArrayServerStreamSendCode},
 		}},
 		{"streaming-result-primitive-map", testdata.StreamingResultPrimitiveMapDSL, []*sectionExpectation{
-			{"server-stream-send", &testdata.StreamingResultPrimitiveMapServerStreamSendCode},
+			{"server-websocket-send", &testdata.StreamingResultPrimitiveMapServerStreamSendCode},
 		}},
 		{"streaming-result-user-type-array", testdata.StreamingResultUserTypeArrayDSL, []*sectionExpectation{
-			{"server-stream-send", &testdata.StreamingResultUserTypeArrayServerStreamSendCode},
+			{"server-websocket-send", &testdata.StreamingResultUserTypeArrayServerStreamSendCode},
 		}},
 		{"streaming-result-user-type-map", testdata.StreamingResultUserTypeMapDSL, []*sectionExpectation{
-			{"server-stream-send", &testdata.StreamingResultUserTypeMapServerStreamSendCode},
+			{"server-websocket-send", &testdata.StreamingResultUserTypeMapServerStreamSendCode},
 		}},
 		{"streaming-result-no-payload", testdata.StreamingResultNoPayloadDSL, []*sectionExpectation{
 			{"server-handler-init", &testdata.StreamingResultNoPayloadServerHandlerInitCode},
@@ -83,118 +83,118 @@ func TestServerStreaming(t *testing.T) {
 
 		{"streaming-payload", testdata.StreamingPayloadDSL, []*sectionExpectation{
 			{"server-handler-init", &testdata.StreamingPayloadServerHandlerInitCode},
-			{"server-stream-send", &testdata.StreamingPayloadServerStreamSendCode},
-			{"server-stream-recv", &testdata.StreamingPayloadServerStreamRecvCode},
-			{"server-stream-close", nil},
-			{"server-stream-set-view", nil},
+			{"server-websocket-send", &testdata.StreamingPayloadServerStreamSendCode},
+			{"server-websocket-recv", &testdata.StreamingPayloadServerStreamRecvCode},
+			{"server-websocket-close", nil},
+			{"server-websocket-set-view", nil},
 		}},
 		{"streaming-payload-no-payload", testdata.StreamingPayloadNoPayloadDSL, []*sectionExpectation{
 			{"server-handler-init", &testdata.StreamingPayloadNoPayloadServerHandlerInitCode},
-			{"server-stream-close", nil},
+			{"server-websocket-close", nil},
 		}},
 		{"streaming-payload-no-result", testdata.StreamingPayloadNoResultDSL, []*sectionExpectation{
-			{"server-stream-send", nil},
-			{"server-stream-recv", &testdata.StreamingPayloadNoResultServerStreamRecvCode},
-			{"server-stream-close", &testdata.StreamingPayloadNoResultServerStreamCloseCode},
-			{"server-stream-set-view", nil},
+			{"server-websocket-send", nil},
+			{"server-websocket-recv", &testdata.StreamingPayloadNoResultServerStreamRecvCode},
+			{"server-websocket-close", &testdata.StreamingPayloadNoResultServerStreamCloseCode},
+			{"server-websocket-set-view", nil},
 		}},
 		{"streaming-payload-result-with-views", testdata.StreamingPayloadResultWithViewsDSL, []*sectionExpectation{
-			{"server-stream-send", &testdata.StreamingPayloadResultWithViewsServerStreamSendCode},
-			{"server-stream-recv", &testdata.StreamingPayloadResultWithViewsServerStreamRecvCode},
-			{"server-stream-close", nil},
-			{"server-stream-set-view", &testdata.StreamingPayloadResultWithViewsServerStreamSetViewCode},
+			{"server-websocket-send", &testdata.StreamingPayloadResultWithViewsServerStreamSendCode},
+			{"server-websocket-recv", &testdata.StreamingPayloadResultWithViewsServerStreamRecvCode},
+			{"server-websocket-close", nil},
+			{"server-websocket-set-view", &testdata.StreamingPayloadResultWithViewsServerStreamSetViewCode},
 		}},
 		{"streaming-payload-result-with-explicit-view", testdata.StreamingPayloadResultWithExplicitViewDSL, []*sectionExpectation{
-			{"server-stream-send", &testdata.StreamingPayloadResultWithExplicitViewServerStreamSendCode},
-			{"server-stream-recv", &testdata.StreamingPayloadResultWithExplicitViewServerStreamRecvCode},
-			{"server-stream-set-view", nil},
+			{"server-websocket-send", &testdata.StreamingPayloadResultWithExplicitViewServerStreamSendCode},
+			{"server-websocket-recv", &testdata.StreamingPayloadResultWithExplicitViewServerStreamRecvCode},
+			{"server-websocket-set-view", nil},
 		}},
 		{"streaming-payload-result-collection-with-views", testdata.StreamingPayloadResultCollectionWithViewsDSL, []*sectionExpectation{
-			{"server-stream-send", &testdata.StreamingPayloadResultCollectionWithViewsServerStreamSendCode},
-			{"server-stream-recv", &testdata.StreamingPayloadResultCollectionWithViewsServerStreamRecvCode},
-			{"server-stream-set-view", &testdata.StreamingPayloadResultCollectionWithViewsServerStreamSetViewCode},
+			{"server-websocket-send", &testdata.StreamingPayloadResultCollectionWithViewsServerStreamSendCode},
+			{"server-websocket-recv", &testdata.StreamingPayloadResultCollectionWithViewsServerStreamRecvCode},
+			{"server-websocket-set-view", &testdata.StreamingPayloadResultCollectionWithViewsServerStreamSetViewCode},
 		}},
 		{"streaming-payload-result-collection-with-explicit-view", testdata.StreamingPayloadResultCollectionWithExplicitViewDSL, []*sectionExpectation{
-			{"server-stream-send", &testdata.StreamingPayloadResultCollectionWithExplicitViewServerStreamSendCode},
-			{"server-stream-recv", &testdata.StreamingPayloadResultCollectionWithExplicitViewServerStreamRecvCode},
-			{"server-stream-set-view", nil},
+			{"server-websocket-send", &testdata.StreamingPayloadResultCollectionWithExplicitViewServerStreamSendCode},
+			{"server-websocket-recv", &testdata.StreamingPayloadResultCollectionWithExplicitViewServerStreamRecvCode},
+			{"server-websocket-set-view", nil},
 		}},
 		{"streaming-payload-primitive", testdata.StreamingPayloadPrimitiveDSL, []*sectionExpectation{
-			{"server-stream-send", &testdata.StreamingPayloadPrimitiveServerStreamSendCode},
-			{"server-stream-recv", &testdata.StreamingPayloadPrimitiveServerStreamRecvCode},
-			{"server-stream-set-view", nil},
+			{"server-websocket-send", &testdata.StreamingPayloadPrimitiveServerStreamSendCode},
+			{"server-websocket-recv", &testdata.StreamingPayloadPrimitiveServerStreamRecvCode},
+			{"server-websocket-set-view", nil},
 		}},
 		{"streaming-payload-primitive-array", testdata.StreamingPayloadPrimitiveArrayDSL, []*sectionExpectation{
-			{"server-stream-send", &testdata.StreamingPayloadPrimitiveArrayServerStreamSendCode},
-			{"server-stream-recv", &testdata.StreamingPayloadPrimitiveArrayServerStreamRecvCode},
+			{"server-websocket-send", &testdata.StreamingPayloadPrimitiveArrayServerStreamSendCode},
+			{"server-websocket-recv", &testdata.StreamingPayloadPrimitiveArrayServerStreamRecvCode},
 		}},
 		{"streaming-payload-primitive-map", testdata.StreamingPayloadPrimitiveMapDSL, []*sectionExpectation{
-			{"server-stream-send", &testdata.StreamingPayloadPrimitiveMapServerStreamSendCode},
-			{"server-stream-recv", &testdata.StreamingPayloadPrimitiveMapServerStreamRecvCode},
+			{"server-websocket-send", &testdata.StreamingPayloadPrimitiveMapServerStreamSendCode},
+			{"server-websocket-recv", &testdata.StreamingPayloadPrimitiveMapServerStreamRecvCode},
 		}},
 		{"streaming-payload-user-type-array", testdata.StreamingPayloadUserTypeArrayDSL, []*sectionExpectation{
-			{"server-stream-send", &testdata.StreamingPayloadUserTypeArrayServerStreamSendCode},
-			{"server-stream-recv", &testdata.StreamingPayloadUserTypeArrayServerStreamRecvCode},
+			{"server-websocket-send", &testdata.StreamingPayloadUserTypeArrayServerStreamSendCode},
+			{"server-websocket-recv", &testdata.StreamingPayloadUserTypeArrayServerStreamRecvCode},
 		}},
 		{"streaming-payload-user-type-map", testdata.StreamingPayloadUserTypeMapDSL, []*sectionExpectation{
-			{"server-stream-send", &testdata.StreamingPayloadUserTypeMapServerStreamSendCode},
-			{"server-stream-recv", &testdata.StreamingPayloadUserTypeMapServerStreamRecvCode},
+			{"server-websocket-send", &testdata.StreamingPayloadUserTypeMapServerStreamSendCode},
+			{"server-websocket-recv", &testdata.StreamingPayloadUserTypeMapServerStreamRecvCode},
 		}},
 
 		// bidirectional streaming
 
 		{"bidirectional-streaming", testdata.BidirectionalStreamingDSL, []*sectionExpectation{
 			{"server-handler-init", &testdata.BidirectionalStreamingServerHandlerInitCode},
-			{"server-stream-send", &testdata.BidirectionalStreamingServerStreamSendCode},
-			{"server-stream-recv", &testdata.BidirectionalStreamingServerStreamRecvCode},
-			{"server-stream-close", &testdata.BidirectionalStreamingServerStreamCloseCode},
-			{"server-stream-set-view", nil},
+			{"server-websocket-send", &testdata.BidirectionalStreamingServerStreamSendCode},
+			{"server-websocket-recv", &testdata.BidirectionalStreamingServerStreamRecvCode},
+			{"server-websocket-close", &testdata.BidirectionalStreamingServerStreamCloseCode},
+			{"server-websocket-set-view", nil},
 		}},
 		{"bidirectional-streaming-no-payload", testdata.BidirectionalStreamingNoPayloadDSL, []*sectionExpectation{
 			{"server-handler-init", &testdata.BidirectionalStreamingNoPayloadServerHandlerInitCode},
-			{"server-stream-close", &testdata.BidirectionalStreamingNoPayloadServerStreamCloseCode},
+			{"server-websocket-close", &testdata.BidirectionalStreamingNoPayloadServerStreamCloseCode},
 		}},
 		{"bidirectional-streaming-result-with-views", testdata.BidirectionalStreamingResultWithViewsDSL, []*sectionExpectation{
-			{"server-stream-send", &testdata.BidirectionalStreamingResultWithViewsServerStreamSendCode},
-			{"server-stream-recv", &testdata.BidirectionalStreamingResultWithViewsServerStreamRecvCode},
-			{"server-stream-close", &testdata.BidirectionalStreamingResultWithViewsServerStreamCloseCode},
-			{"server-stream-set-view", &testdata.BidirectionalStreamingResultWithViewsServerStreamSetViewCode},
+			{"server-websocket-send", &testdata.BidirectionalStreamingResultWithViewsServerStreamSendCode},
+			{"server-websocket-recv", &testdata.BidirectionalStreamingResultWithViewsServerStreamRecvCode},
+			{"server-websocket-close", &testdata.BidirectionalStreamingResultWithViewsServerStreamCloseCode},
+			{"server-websocket-set-view", &testdata.BidirectionalStreamingResultWithViewsServerStreamSetViewCode},
 		}},
 		{"bidirectional-streaming-result-with-explicit-view", testdata.BidirectionalStreamingResultWithExplicitViewDSL, []*sectionExpectation{
-			{"server-stream-send", &testdata.BidirectionalStreamingResultWithExplicitViewServerStreamSendCode},
-			{"server-stream-recv", &testdata.BidirectionalStreamingResultWithExplicitViewServerStreamRecvCode},
-			{"server-stream-set-view", nil},
+			{"server-websocket-send", &testdata.BidirectionalStreamingResultWithExplicitViewServerStreamSendCode},
+			{"server-websocket-recv", &testdata.BidirectionalStreamingResultWithExplicitViewServerStreamRecvCode},
+			{"server-websocket-set-view", nil},
 		}},
 		{"bidirectional-streaming-result-collection-with-views", testdata.BidirectionalStreamingResultCollectionWithViewsDSL, []*sectionExpectation{
-			{"server-stream-send", &testdata.BidirectionalStreamingResultCollectionWithViewsServerStreamSendCode},
-			{"server-stream-recv", &testdata.BidirectionalStreamingResultCollectionWithViewsServerStreamRecvCode},
-			{"server-stream-set-view", &testdata.BidirectionalStreamingResultCollectionWithViewsServerStreamSetViewCode},
+			{"server-websocket-send", &testdata.BidirectionalStreamingResultCollectionWithViewsServerStreamSendCode},
+			{"server-websocket-recv", &testdata.BidirectionalStreamingResultCollectionWithViewsServerStreamRecvCode},
+			{"server-websocket-set-view", &testdata.BidirectionalStreamingResultCollectionWithViewsServerStreamSetViewCode},
 		}},
 		{"bidirectional-streaming-result-collection-with-explicit-view", testdata.BidirectionalStreamingResultCollectionWithExplicitViewDSL, []*sectionExpectation{
-			{"server-stream-send", &testdata.BidirectionalStreamingResultCollectionWithExplicitViewServerStreamSendCode},
-			{"server-stream-recv", &testdata.BidirectionalStreamingResultCollectionWithExplicitViewServerStreamRecvCode},
-			{"server-stream-set-view", nil},
+			{"server-websocket-send", &testdata.BidirectionalStreamingResultCollectionWithExplicitViewServerStreamSendCode},
+			{"server-websocket-recv", &testdata.BidirectionalStreamingResultCollectionWithExplicitViewServerStreamRecvCode},
+			{"server-websocket-set-view", nil},
 		}},
 		{"bidirectional-streaming-primitive", testdata.BidirectionalStreamingPrimitiveDSL, []*sectionExpectation{
-			{"server-stream-send", &testdata.BidirectionalStreamingPrimitiveServerStreamSendCode},
-			{"server-stream-recv", &testdata.BidirectionalStreamingPrimitiveServerStreamRecvCode},
-			{"server-stream-set-view", nil},
+			{"server-websocket-send", &testdata.BidirectionalStreamingPrimitiveServerStreamSendCode},
+			{"server-websocket-recv", &testdata.BidirectionalStreamingPrimitiveServerStreamRecvCode},
+			{"server-websocket-set-view", nil},
 		}},
 		{"bidirectional-streaming-primitive-array", testdata.BidirectionalStreamingPrimitiveArrayDSL, []*sectionExpectation{
-			{"server-stream-send", &testdata.BidirectionalStreamingPrimitiveArrayServerStreamSendCode},
-			{"server-stream-recv", &testdata.BidirectionalStreamingPrimitiveArrayServerStreamRecvCode},
+			{"server-websocket-send", &testdata.BidirectionalStreamingPrimitiveArrayServerStreamSendCode},
+			{"server-websocket-recv", &testdata.BidirectionalStreamingPrimitiveArrayServerStreamRecvCode},
 		}},
 		{"bidirectional-streaming-primitive-map", testdata.BidirectionalStreamingPrimitiveMapDSL, []*sectionExpectation{
-			{"server-stream-send", &testdata.BidirectionalStreamingPrimitiveMapServerStreamSendCode},
-			{"server-stream-recv", &testdata.BidirectionalStreamingPrimitiveMapServerStreamRecvCode},
+			{"server-websocket-send", &testdata.BidirectionalStreamingPrimitiveMapServerStreamSendCode},
+			{"server-websocket-recv", &testdata.BidirectionalStreamingPrimitiveMapServerStreamRecvCode},
 		}},
 		{"bidirectional-streaming-user-type-array", testdata.BidirectionalStreamingUserTypeArrayDSL, []*sectionExpectation{
-			{"server-stream-send", &testdata.BidirectionalStreamingUserTypeArrayServerStreamSendCode},
-			{"server-stream-recv", &testdata.BidirectionalStreamingUserTypeArrayServerStreamRecvCode},
+			{"server-websocket-send", &testdata.BidirectionalStreamingUserTypeArrayServerStreamSendCode},
+			{"server-websocket-recv", &testdata.BidirectionalStreamingUserTypeArrayServerStreamRecvCode},
 		}},
 		{"bidirectional-streaming-user-type-map", testdata.BidirectionalStreamingUserTypeMapDSL, []*sectionExpectation{
-			{"server-stream-send", &testdata.BidirectionalStreamingUserTypeMapServerStreamSendCode},
-			{"server-stream-recv", &testdata.BidirectionalStreamingUserTypeMapServerStreamRecvCode},
+			{"server-websocket-send", &testdata.BidirectionalStreamingUserTypeMapServerStreamSendCode},
+			{"server-websocket-recv", &testdata.BidirectionalStreamingUserTypeMapServerStreamRecvCode},
 		}},
 	}
 
@@ -205,52 +205,52 @@ func TestServerStreaming(t *testing.T) {
 func TestClientStreaming(t *testing.T) {
 	cases := []*testCase{
 		{"mixed-endpoints", testdata.StreamingResultDSL, []*sectionExpectation{
-			{"client-stream-conn-configurer-struct", &testdata.MixedEndpointsConnConfigurerStructCode},
-			{"client-stream-conn-configurer-struct-init", &testdata.MixedEndpointsConnConfigurerInitCode},
+			{"client-websocket-conn-configurer-struct", &testdata.MixedEndpointsConnConfigurerStructCode},
+			{"client-websocket-conn-configurer-struct-init", &testdata.MixedEndpointsConnConfigurerInitCode},
 		}},
 
 		// streaming result
 		{"streaming-result", testdata.StreamingResultDSL, []*sectionExpectation{
 			{"client-endpoint-init", &testdata.StreamingResultClientEndpointCode},
-			{"client-stream-recv", &testdata.StreamingResultClientStreamRecvCode},
-			{"client-stream-close", nil},
-			{"client-stream-set-view", nil},
+			{"client-websocket-recv", &testdata.StreamingResultClientStreamRecvCode},
+			{"client-websocket-close", nil},
+			{"client-websocket-set-view", nil},
 		}},
 		{"streaming-result-with-views", testdata.StreamingResultWithViewsDSL, []*sectionExpectation{
 			{"client-endpoint-init", &testdata.StreamingResultWithViewsClientEndpointCode},
-			{"client-stream-recv", &testdata.StreamingResultWithViewsClientStreamRecvCode},
-			{"client-stream-close", nil},
-			{"client-stream-set-view", &testdata.StreamingResultWithViewsClientStreamSetViewCode},
+			{"client-websocket-recv", &testdata.StreamingResultWithViewsClientStreamRecvCode},
+			{"client-websocket-close", nil},
+			{"client-websocket-set-view", &testdata.StreamingResultWithViewsClientStreamSetViewCode},
 		}},
 		{"streaming-result-with-explicit-view", testdata.StreamingResultWithExplicitViewDSL, []*sectionExpectation{
 			{"client-endpoint-init", &testdata.StreamingResultWithExplicitViewClientEndpointCode},
-			{"client-stream-recv", &testdata.StreamingResultWithExplicitViewClientStreamRecvCode},
-			{"client-stream-set-view", nil},
+			{"client-websocket-recv", &testdata.StreamingResultWithExplicitViewClientStreamRecvCode},
+			{"client-websocket-set-view", nil},
 		}},
 		{"streaming-result-collection-with-views", testdata.StreamingResultCollectionWithViewsDSL, []*sectionExpectation{
-			{"client-stream-recv", &testdata.StreamingResultCollectionWithViewsClientStreamRecvCode},
-			{"client-stream-set-view", &testdata.StreamingResultCollectionWithViewsClientStreamSetViewCode},
+			{"client-websocket-recv", &testdata.StreamingResultCollectionWithViewsClientStreamRecvCode},
+			{"client-websocket-set-view", &testdata.StreamingResultCollectionWithViewsClientStreamSetViewCode},
 		}},
 		{"streaming-result-collection-with-explicit-view", testdata.StreamingResultCollectionWithExplicitViewDSL, []*sectionExpectation{
 			{"client-endpoint-init", &testdata.StreamingResultCollectionWithExplicitViewClientEndpointCode},
-			{"client-stream-recv", &testdata.StreamingResultCollectionWithExplicitViewClientStreamRecvCode},
-			{"client-stream-set-view", nil},
+			{"client-websocket-recv", &testdata.StreamingResultCollectionWithExplicitViewClientStreamRecvCode},
+			{"client-websocket-set-view", nil},
 		}},
 		{"streaming-result-primitive", testdata.StreamingResultPrimitiveDSL, []*sectionExpectation{
-			{"client-stream-recv", &testdata.StreamingResultPrimitiveClientStreamRecvCode},
-			{"client-stream-set-view", nil},
+			{"client-websocket-recv", &testdata.StreamingResultPrimitiveClientStreamRecvCode},
+			{"client-websocket-set-view", nil},
 		}},
 		{"streaming-result-primitive-array", testdata.StreamingResultPrimitiveArrayDSL, []*sectionExpectation{
-			{"client-stream-recv", &testdata.StreamingResultPrimitiveArrayClientStreamRecvCode},
+			{"client-websocket-recv", &testdata.StreamingResultPrimitiveArrayClientStreamRecvCode},
 		}},
 		{"streaming-result-primitive-map", testdata.StreamingResultPrimitiveMapDSL, []*sectionExpectation{
-			{"client-stream-recv", &testdata.StreamingResultPrimitiveMapClientStreamRecvCode},
+			{"client-websocket-recv", &testdata.StreamingResultPrimitiveMapClientStreamRecvCode},
 		}},
 		{"streaming-result-user-type-array", testdata.StreamingResultUserTypeArrayDSL, []*sectionExpectation{
-			{"client-stream-recv", &testdata.StreamingResultUserTypeArrayClientStreamRecvCode},
+			{"client-websocket-recv", &testdata.StreamingResultUserTypeArrayClientStreamRecvCode},
 		}},
 		{"streaming-result-user-type-map", testdata.StreamingResultUserTypeMapDSL, []*sectionExpectation{
-			{"client-stream-recv", &testdata.StreamingResultUserTypeMapClientStreamRecvCode},
+			{"client-websocket-recv", &testdata.StreamingResultUserTypeMapClientStreamRecvCode},
 		}},
 		{"streaming-result-no-payload", testdata.StreamingResultNoPayloadDSL, []*sectionExpectation{
 			{"client-endpoint-init", &testdata.StreamingResultNoPayloadClientEndpointCode},
@@ -260,122 +260,122 @@ func TestClientStreaming(t *testing.T) {
 
 		{"streaming-payload", testdata.StreamingPayloadDSL, []*sectionExpectation{
 			{"client-endpoint-init", &testdata.StreamingPayloadClientEndpointCode},
-			{"client-stream-send", &testdata.StreamingPayloadClientStreamSendCode},
-			{"client-stream-recv", &testdata.StreamingPayloadClientStreamRecvCode},
-			{"client-stream-close", nil},
-			{"client-stream-set-view", nil},
+			{"client-websocket-send", &testdata.StreamingPayloadClientStreamSendCode},
+			{"client-websocket-recv", &testdata.StreamingPayloadClientStreamRecvCode},
+			{"client-websocket-close", nil},
+			{"client-websocket-set-view", nil},
 		}},
 		{"streaming-payload-no-payload", testdata.StreamingPayloadNoPayloadDSL, []*sectionExpectation{
 			{"client-endpoint-init", &testdata.StreamingPayloadNoPayloadClientEndpointCode},
-			{"client-stream-send", &testdata.StreamingPayloadNoPayloadClientStreamSendCode},
-			{"client-stream-recv", &testdata.StreamingPayloadNoPayloadClientStreamRecvCode},
-			{"client-stream-close", nil},
+			{"client-websocket-send", &testdata.StreamingPayloadNoPayloadClientStreamSendCode},
+			{"client-websocket-recv", &testdata.StreamingPayloadNoPayloadClientStreamRecvCode},
+			{"client-websocket-close", nil},
 		}},
 		{"streaming-payload-no-result", testdata.StreamingPayloadNoResultDSL, []*sectionExpectation{
-			{"client-stream-send", &testdata.StreamingPayloadNoResultClientStreamSendCode},
-			{"client-stream-recv", nil},
-			{"client-stream-close", &testdata.StreamingPayloadNoResultClientStreamCloseCode},
-			{"client-stream-set-view", nil},
+			{"client-websocket-send", &testdata.StreamingPayloadNoResultClientStreamSendCode},
+			{"client-websocket-recv", nil},
+			{"client-websocket-close", &testdata.StreamingPayloadNoResultClientStreamCloseCode},
+			{"client-websocket-set-view", nil},
 		}},
 		{"streaming-payload-result-with-views", testdata.StreamingPayloadResultWithViewsDSL, []*sectionExpectation{
-			{"client-stream-send", &testdata.StreamingPayloadResultWithViewsClientStreamSendCode},
-			{"client-stream-recv", &testdata.StreamingPayloadResultWithViewsClientStreamRecvCode},
-			{"client-stream-close", nil},
-			{"client-stream-set-view", &testdata.StreamingPayloadResultWithViewsClientStreamSetViewCode},
+			{"client-websocket-send", &testdata.StreamingPayloadResultWithViewsClientStreamSendCode},
+			{"client-websocket-recv", &testdata.StreamingPayloadResultWithViewsClientStreamRecvCode},
+			{"client-websocket-close", nil},
+			{"client-websocket-set-view", &testdata.StreamingPayloadResultWithViewsClientStreamSetViewCode},
 		}},
 		{"streaming-payload-result-with-explicit-view", testdata.StreamingPayloadResultWithExplicitViewDSL, []*sectionExpectation{
-			{"client-stream-send", &testdata.StreamingPayloadResultWithExplicitViewClientStreamSendCode},
-			{"client-stream-recv", &testdata.StreamingPayloadResultWithExplicitViewClientStreamRecvCode},
-			{"client-stream-set-view", nil},
+			{"client-websocket-send", &testdata.StreamingPayloadResultWithExplicitViewClientStreamSendCode},
+			{"client-websocket-recv", &testdata.StreamingPayloadResultWithExplicitViewClientStreamRecvCode},
+			{"client-websocket-set-view", nil},
 		}},
 		{"streaming-payload-result-collection-with-views", testdata.StreamingPayloadResultCollectionWithViewsDSL, []*sectionExpectation{
-			{"client-stream-send", &testdata.StreamingPayloadResultCollectionWithViewsClientStreamSendCode},
-			{"client-stream-recv", &testdata.StreamingPayloadResultCollectionWithViewsClientStreamRecvCode},
-			{"client-stream-set-view", &testdata.StreamingPayloadResultCollectionWithViewsClientStreamSetViewCode},
+			{"client-websocket-send", &testdata.StreamingPayloadResultCollectionWithViewsClientStreamSendCode},
+			{"client-websocket-recv", &testdata.StreamingPayloadResultCollectionWithViewsClientStreamRecvCode},
+			{"client-websocket-set-view", &testdata.StreamingPayloadResultCollectionWithViewsClientStreamSetViewCode},
 		}},
 		{"streaming-payload-result-collection-with-explicit-view", testdata.StreamingPayloadResultCollectionWithExplicitViewDSL, []*sectionExpectation{
-			{"client-stream-send", &testdata.StreamingPayloadResultCollectionWithExplicitViewClientStreamSendCode},
-			{"client-stream-recv", &testdata.StreamingPayloadResultCollectionWithExplicitViewClientStreamRecvCode},
-			{"client-stream-set-view", nil},
+			{"client-websocket-send", &testdata.StreamingPayloadResultCollectionWithExplicitViewClientStreamSendCode},
+			{"client-websocket-recv", &testdata.StreamingPayloadResultCollectionWithExplicitViewClientStreamRecvCode},
+			{"client-websocket-set-view", nil},
 		}},
 		{"streaming-payload-primitive", testdata.StreamingPayloadPrimitiveDSL, []*sectionExpectation{
-			{"client-stream-send", &testdata.StreamingPayloadPrimitiveClientStreamSendCode},
-			{"client-stream-recv", &testdata.StreamingPayloadPrimitiveClientStreamRecvCode},
-			{"client-stream-set-view", nil},
+			{"client-websocket-send", &testdata.StreamingPayloadPrimitiveClientStreamSendCode},
+			{"client-websocket-recv", &testdata.StreamingPayloadPrimitiveClientStreamRecvCode},
+			{"client-websocket-set-view", nil},
 		}},
 		{"streaming-payload-primitive-array", testdata.StreamingPayloadPrimitiveArrayDSL, []*sectionExpectation{
-			{"client-stream-send", &testdata.StreamingPayloadPrimitiveArrayClientStreamSendCode},
-			{"client-stream-recv", &testdata.StreamingPayloadPrimitiveArrayClientStreamRecvCode},
+			{"client-websocket-send", &testdata.StreamingPayloadPrimitiveArrayClientStreamSendCode},
+			{"client-websocket-recv", &testdata.StreamingPayloadPrimitiveArrayClientStreamRecvCode},
 		}},
 		{"streaming-payload-primitive-map", testdata.StreamingPayloadPrimitiveMapDSL, []*sectionExpectation{
-			{"client-stream-send", &testdata.StreamingPayloadPrimitiveMapClientStreamSendCode},
-			{"client-stream-recv", &testdata.StreamingPayloadPrimitiveMapClientStreamRecvCode},
+			{"client-websocket-send", &testdata.StreamingPayloadPrimitiveMapClientStreamSendCode},
+			{"client-websocket-recv", &testdata.StreamingPayloadPrimitiveMapClientStreamRecvCode},
 		}},
 		{"streaming-payload-user-type-array", testdata.StreamingPayloadUserTypeArrayDSL, []*sectionExpectation{
-			{"client-stream-send", &testdata.StreamingPayloadUserTypeArrayClientStreamSendCode},
-			{"client-stream-recv", &testdata.StreamingPayloadUserTypeArrayClientStreamRecvCode},
+			{"client-websocket-send", &testdata.StreamingPayloadUserTypeArrayClientStreamSendCode},
+			{"client-websocket-recv", &testdata.StreamingPayloadUserTypeArrayClientStreamRecvCode},
 		}},
 		{"streaming-payload-user-type-map", testdata.StreamingPayloadUserTypeMapDSL, []*sectionExpectation{
-			{"client-stream-send", &testdata.StreamingPayloadUserTypeMapClientStreamSendCode},
-			{"client-stream-recv", &testdata.StreamingPayloadUserTypeMapClientStreamRecvCode},
+			{"client-websocket-send", &testdata.StreamingPayloadUserTypeMapClientStreamSendCode},
+			{"client-websocket-recv", &testdata.StreamingPayloadUserTypeMapClientStreamRecvCode},
 		}},
 
 		// bidirectional streaming
 
 		{"bidirectional-streaming", testdata.BidirectionalStreamingDSL, []*sectionExpectation{
 			{"client-endpoint-init", &testdata.BidirectionalStreamingClientEndpointCode},
-			{"client-stream-send", &testdata.BidirectionalStreamingClientStreamSendCode},
-			{"client-stream-recv", &testdata.BidirectionalStreamingClientStreamRecvCode},
-			{"client-stream-close", &testdata.BidirectionalStreamingClientStreamCloseCode},
-			{"client-stream-set-view", nil},
+			{"client-websocket-send", &testdata.BidirectionalStreamingClientStreamSendCode},
+			{"client-websocket-recv", &testdata.BidirectionalStreamingClientStreamRecvCode},
+			{"client-websocket-close", &testdata.BidirectionalStreamingClientStreamCloseCode},
+			{"client-websocket-set-view", nil},
 		}},
 		{"bidirectional-streaming-no-payload", testdata.BidirectionalStreamingNoPayloadDSL, []*sectionExpectation{
 			{"client-endpoint-init", &testdata.BidirectionalStreamingNoPayloadClientEndpointCode},
-			{"client-stream-send", &testdata.BidirectionalStreamingNoPayloadClientStreamSendCode},
-			{"client-stream-recv", &testdata.BidirectionalStreamingNoPayloadClientStreamRecvCode},
-			{"client-stream-close", &testdata.BidirectionalStreamingNoPayloadClientStreamCloseCode},
+			{"client-websocket-send", &testdata.BidirectionalStreamingNoPayloadClientStreamSendCode},
+			{"client-websocket-recv", &testdata.BidirectionalStreamingNoPayloadClientStreamRecvCode},
+			{"client-websocket-close", &testdata.BidirectionalStreamingNoPayloadClientStreamCloseCode},
 		}},
 		{"bidirectional-streaming-result-with-views", testdata.BidirectionalStreamingResultWithViewsDSL, []*sectionExpectation{
-			{"client-stream-send", &testdata.BidirectionalStreamingResultWithViewsClientStreamSendCode},
-			{"client-stream-recv", &testdata.BidirectionalStreamingResultWithViewsClientStreamRecvCode},
-			{"client-stream-close", &testdata.BidirectionalStreamingResultWithViewsClientStreamCloseCode},
-			{"client-stream-set-view", &testdata.BidirectionalStreamingResultWithViewsClientStreamSetViewCode},
+			{"client-websocket-send", &testdata.BidirectionalStreamingResultWithViewsClientStreamSendCode},
+			{"client-websocket-recv", &testdata.BidirectionalStreamingResultWithViewsClientStreamRecvCode},
+			{"client-websocket-close", &testdata.BidirectionalStreamingResultWithViewsClientStreamCloseCode},
+			{"client-websocket-set-view", &testdata.BidirectionalStreamingResultWithViewsClientStreamSetViewCode},
 		}},
 		{"bidirectional-streaming-result-with-explicit-view", testdata.BidirectionalStreamingResultWithExplicitViewDSL, []*sectionExpectation{
-			{"client-stream-send", &testdata.BidirectionalStreamingResultWithExplicitViewClientStreamSendCode},
-			{"client-stream-recv", &testdata.BidirectionalStreamingResultWithExplicitViewClientStreamRecvCode},
-			{"client-stream-set-view", nil},
+			{"client-websocket-send", &testdata.BidirectionalStreamingResultWithExplicitViewClientStreamSendCode},
+			{"client-websocket-recv", &testdata.BidirectionalStreamingResultWithExplicitViewClientStreamRecvCode},
+			{"client-websocket-set-view", nil},
 		}},
 		{"bidirectional-streaming-result-collection-with-views", testdata.BidirectionalStreamingResultCollectionWithViewsDSL, []*sectionExpectation{
-			{"client-stream-send", &testdata.BidirectionalStreamingResultCollectionWithViewsClientStreamSendCode},
-			{"client-stream-recv", &testdata.BidirectionalStreamingResultCollectionWithViewsClientStreamRecvCode},
-			{"client-stream-set-view", &testdata.BidirectionalStreamingResultCollectionWithViewsClientStreamSetViewCode},
+			{"client-websocket-send", &testdata.BidirectionalStreamingResultCollectionWithViewsClientStreamSendCode},
+			{"client-websocket-recv", &testdata.BidirectionalStreamingResultCollectionWithViewsClientStreamRecvCode},
+			{"client-websocket-set-view", &testdata.BidirectionalStreamingResultCollectionWithViewsClientStreamSetViewCode},
 		}},
 		{"bidirectional-streaming-result-collection-with-explicit-view", testdata.BidirectionalStreamingResultCollectionWithExplicitViewDSL, []*sectionExpectation{
-			{"client-stream-send", &testdata.BidirectionalStreamingResultCollectionWithExplicitViewClientStreamSendCode},
-			{"client-stream-recv", &testdata.BidirectionalStreamingResultCollectionWithExplicitViewClientStreamRecvCode},
-			{"client-stream-set-view", nil},
+			{"client-websocket-send", &testdata.BidirectionalStreamingResultCollectionWithExplicitViewClientStreamSendCode},
+			{"client-websocket-recv", &testdata.BidirectionalStreamingResultCollectionWithExplicitViewClientStreamRecvCode},
+			{"client-websocket-set-view", nil},
 		}},
 		{"bidirectional-streaming-primitive", testdata.BidirectionalStreamingPrimitiveDSL, []*sectionExpectation{
-			{"client-stream-send", &testdata.BidirectionalStreamingPrimitiveClientStreamSendCode},
-			{"client-stream-recv", &testdata.BidirectionalStreamingPrimitiveClientStreamRecvCode},
-			{"client-stream-set-view", nil},
+			{"client-websocket-send", &testdata.BidirectionalStreamingPrimitiveClientStreamSendCode},
+			{"client-websocket-recv", &testdata.BidirectionalStreamingPrimitiveClientStreamRecvCode},
+			{"client-websocket-set-view", nil},
 		}},
 		{"bidirectional-streaming-primitive-array", testdata.BidirectionalStreamingPrimitiveArrayDSL, []*sectionExpectation{
-			{"client-stream-send", &testdata.BidirectionalStreamingPrimitiveArrayClientStreamSendCode},
-			{"client-stream-recv", &testdata.BidirectionalStreamingPrimitiveArrayClientStreamRecvCode},
+			{"client-websocket-send", &testdata.BidirectionalStreamingPrimitiveArrayClientStreamSendCode},
+			{"client-websocket-recv", &testdata.BidirectionalStreamingPrimitiveArrayClientStreamRecvCode},
 		}},
 		{"bidirectional-streaming-primitive-map", testdata.BidirectionalStreamingPrimitiveMapDSL, []*sectionExpectation{
-			{"client-stream-send", &testdata.BidirectionalStreamingPrimitiveMapClientStreamSendCode},
-			{"client-stream-recv", &testdata.BidirectionalStreamingPrimitiveMapClientStreamRecvCode},
+			{"client-websocket-send", &testdata.BidirectionalStreamingPrimitiveMapClientStreamSendCode},
+			{"client-websocket-recv", &testdata.BidirectionalStreamingPrimitiveMapClientStreamRecvCode},
 		}},
 		{"bidirectional-streaming-user-type-array", testdata.BidirectionalStreamingUserTypeArrayDSL, []*sectionExpectation{
-			{"client-stream-send", &testdata.BidirectionalStreamingUserTypeArrayClientStreamSendCode},
-			{"client-stream-recv", &testdata.BidirectionalStreamingUserTypeArrayClientStreamRecvCode},
+			{"client-websocket-send", &testdata.BidirectionalStreamingUserTypeArrayClientStreamSendCode},
+			{"client-websocket-recv", &testdata.BidirectionalStreamingUserTypeArrayClientStreamRecvCode},
 		}},
 		{"bidirectional-streaming-user-type-map", testdata.BidirectionalStreamingUserTypeMapDSL, []*sectionExpectation{
-			{"client-stream-send", &testdata.BidirectionalStreamingUserTypeMapClientStreamSendCode},
-			{"client-stream-recv", &testdata.BidirectionalStreamingUserTypeMapClientStreamRecvCode},
+			{"client-websocket-send", &testdata.BidirectionalStreamingUserTypeMapClientStreamSendCode},
+			{"client-websocket-recv", &testdata.BidirectionalStreamingUserTypeMapClientStreamRecvCode},
 		}},
 	}
 	filesFn := func() []*codegen.File { return ClientFiles("", expr.Root) }
@@ -392,7 +392,14 @@ func runTests(t *testing.T, cases []*testCase, filesFn func() []*codegen.File) {
 			}
 			for _, s := range c.Sections {
 				var code string
-				f := fs[0]
+				var f *codegen.File
+				if s.Name == "server-handler-init" || s.Name == "client-endpoint-init" {
+					// server.go || client.go
+					f = fs[0]
+				} else {
+					// websocket.go
+					f = fs[1]
+				}
 				sections := f.Section(s.Name)
 				seclen := len(sections)
 				if seclen > 0 {
diff --git a/http/codegen/testdata/handler_init_functions.go b/http/codegen/testdata/handler_init_functions.go
index 50cec3ab..9712f257 100644
--- a/http/codegen/testdata/handler_init_functions.go
+++ b/http/codegen/testdata/handler_init_functions.go
@@ -20,9 +20,7 @@ func NewMethodNoPayloadNoResultHandler(
 		ctx = context.WithValue(ctx, goa.MethodKey, "MethodNoPayloadNoResult")
 		ctx = context.WithValue(ctx, goa.ServiceKey, "ServiceNoPayloadNoResult")
 		var err error
-
 		res, err := endpoint(ctx, nil)
-
 		if err != nil {
 			if err := encodeError(ctx, w, err); err != nil {
 				errhandler(ctx, w, err)
@@ -63,9 +61,7 @@ func NewMethodPayloadNoResultHandler(
 			}
 			return
 		}
-
 		res, err := endpoint(ctx, payload)
-
 		if err != nil {
 			if err := encodeError(ctx, w, err); err != nil {
 				errhandler(ctx, w, err)
@@ -99,9 +95,7 @@ func NewMethodNoPayloadResultHandler(
 		ctx = context.WithValue(ctx, goa.MethodKey, "MethodNoPayloadResult")
 		ctx = context.WithValue(ctx, goa.ServiceKey, "ServiceNoPayloadResult")
 		var err error
-
 		res, err := endpoint(ctx, nil)
-
 		if err != nil {
 			if err := encodeError(ctx, w, err); err != nil {
 				errhandler(ctx, w, err)
@@ -142,9 +136,7 @@ func NewMethodPayloadResultHandler(
 			}
 			return
 		}
-
 		res, err := endpoint(ctx, payload)
-
 		if err != nil {
 			if err := encodeError(ctx, w, err); err != nil {
 				errhandler(ctx, w, err)
@@ -185,9 +177,7 @@ func NewMethodPayloadResultErrorHandler(
 			}
 			return
 		}
-
 		res, err := endpoint(ctx, payload)
-
 		if err != nil {
 			if err := encodeError(ctx, w, err); err != nil {
 				errhandler(ctx, w, err)
diff --git a/http/codegen/testdata/streaming_code.go b/http/codegen/testdata/streaming_code.go
index fd90dd62..26dce361 100644
--- a/http/codegen/testdata/streaming_code.go
+++ b/http/codegen/testdata/streaming_code.go
@@ -44,11 +44,8 @@ func NewStreamingResultMethodHandler(
 			}
 			return
 		}
-
 		var cancel context.CancelFunc
-		{
-			ctx, cancel = context.WithCancel(ctx)
-		}
+		ctx, cancel = context.WithCancel(ctx)
 		v := &streamingresultservice.StreamingResultMethodEndpointInput{
 			Stream: &StreamingResultMethodServerStream{
 				upgrader:   upgrader,
@@ -60,7 +57,6 @@ func NewStreamingResultMethodHandler(
 			Payload: payload.(*streamingresultservice.Request),
 		}
 		_, err = endpoint(ctx, v)
-
 		if err != nil {
 			if _, ok := err.(websocket.HandshakeError); ok {
 				return
@@ -184,11 +180,8 @@ func NewStreamingResultNoPayloadMethodHandler(
 		ctx = context.WithValue(ctx, goa.MethodKey, "StreamingResultNoPayloadMethod")
 		ctx = context.WithValue(ctx, goa.ServiceKey, "StreamingResultNoPayloadService")
 		var err error
-
 		var cancel context.CancelFunc
-		{
-			ctx, cancel = context.WithCancel(ctx)
-		}
+		ctx, cancel = context.WithCancel(ctx)
 		v := &streamingresultnopayloadservice.StreamingResultNoPayloadMethodEndpointInput{
 			Stream: &StreamingResultNoPayloadMethodServerStream{
 				upgrader:   upgrader,
@@ -199,7 +192,6 @@ func NewStreamingResultNoPayloadMethodHandler(
 			},
 		}
 		_, err = endpoint(ctx, v)
-
 		if err != nil {
 			if _, ok := err.(websocket.HandshakeError); ok {
 				return
@@ -230,9 +222,7 @@ func (c *Client) StreamingResultMethod() goa.Endpoint {
 			return nil, err
 		}
 		var cancel context.CancelFunc
-		{
-			ctx, cancel = context.WithCancel(ctx)
-		}
+		ctx, cancel = context.WithCancel(ctx)
 		conn, resp, err := c.dialer.DialContext(ctx, req.URL.String(), req.Header)
 		if err != nil {
 			if resp != nil {
@@ -315,9 +305,7 @@ func (c *Client) StreamingResultWithViewsMethod() goa.Endpoint {
 			return nil, err
 		}
 		var cancel context.CancelFunc
-		{
-			ctx, cancel = context.WithCancel(ctx)
-		}
+		ctx, cancel = context.WithCancel(ctx)
 		conn, resp, err := c.dialer.DialContext(ctx, req.URL.String(), req.Header)
 		if err != nil {
 			if resp != nil {
@@ -395,9 +383,7 @@ func (c *Client) StreamingResultWithExplicitViewMethod() goa.Endpoint {
 			return nil, err
 		}
 		var cancel context.CancelFunc
-		{
-			ctx, cancel = context.WithCancel(ctx)
-		}
+		ctx, cancel = context.WithCancel(ctx)
 		conn, resp, err := c.dialer.DialContext(ctx, req.URL.String(), req.Header)
 		if err != nil {
 			if resp != nil {
@@ -603,9 +589,7 @@ func (c *Client) StreamingResultCollectionWithExplicitViewMethod() goa.Endpoint
 			return nil, err
 		}
 		var cancel context.CancelFunc
-		{
-			ctx, cancel = context.WithCancel(ctx)
-		}
+		ctx, cancel = context.WithCancel(ctx)
 		conn, resp, err := c.dialer.DialContext(ctx, req.URL.String(), req.Header)
 		if err != nil {
 			if resp != nil {
@@ -907,9 +891,7 @@ func (c *Client) StreamingResultNoPayloadMethod() goa.Endpoint {
 			return nil, err
 		}
 		var cancel context.CancelFunc
-		{
-			ctx, cancel = context.WithCancel(ctx)
-		}
+		ctx, cancel = context.WithCancel(ctx)
 		conn, resp, err := c.dialer.DialContext(ctx, req.URL.String(), req.Header)
 		if err != nil {
 			if resp != nil {
@@ -963,11 +945,8 @@ func NewStreamingPayloadMethodHandler(
 			}
 			return
 		}
-
 		var cancel context.CancelFunc
-		{
-			ctx, cancel = context.WithCancel(ctx)
-		}
+		ctx, cancel = context.WithCancel(ctx)
 		v := &streamingpayloadservice.StreamingPayloadMethodEndpointInput{
 			Stream: &StreamingPayloadMethodServerStream{
 				upgrader:   upgrader,
@@ -979,7 +958,6 @@ func NewStreamingPayloadMethodHandler(
 			Payload: payload.(*streamingpayloadservice.Payload),
 		}
 		_, err = endpoint(ctx, v)
-
 		if err != nil {
 			if _, ok := err.(websocket.HandshakeError); ok {
 				return
@@ -1057,9 +1035,7 @@ func (c *Client) StreamingPayloadMethod() goa.Endpoint {
 			return nil, err
 		}
 		var cancel context.CancelFunc
-		{
-			ctx, cancel = context.WithCancel(ctx)
-		}
+		ctx, cancel = context.WithCancel(ctx)
 		conn, resp, err := c.dialer.DialContext(ctx, req.URL.String(), req.Header)
 		if err != nil {
 			if resp != nil {
@@ -1132,11 +1108,8 @@ func NewStreamingPayloadNoPayloadMethodHandler(
 		ctx = context.WithValue(ctx, goa.MethodKey, "StreamingPayloadNoPayloadMethod")
 		ctx = context.WithValue(ctx, goa.ServiceKey, "StreamingPayloadNoPayloadService")
 		var err error
-
 		var cancel context.CancelFunc
-		{
-			ctx, cancel = context.WithCancel(ctx)
-		}
+		ctx, cancel = context.WithCancel(ctx)
 		v := &streamingpayloadnopayloadservice.StreamingPayloadNoPayloadMethodEndpointInput{
 			Stream: &StreamingPayloadNoPayloadMethodServerStream{
 				upgrader:   upgrader,
@@ -1147,7 +1120,6 @@ func NewStreamingPayloadNoPayloadMethodHandler(
 			},
 		}
 		_, err = endpoint(ctx, v)
-
 		if err != nil {
 			if _, ok := err.(websocket.HandshakeError); ok {
 				return
@@ -1174,9 +1146,7 @@ func (c *Client) StreamingPayloadNoPayloadMethod() goa.Endpoint {
 			return nil, err
 		}
 		var cancel context.CancelFunc
-		{
-			ctx, cancel = context.WithCancel(ctx)
-		}
+		ctx, cancel = context.WithCancel(ctx)
 		conn, resp, err := c.dialer.DialContext(ctx, req.URL.String(), req.Header)
 		if err != nil {
 			if resp != nil {
@@ -2132,11 +2102,8 @@ func NewBidirectionalStreamingMethodHandler(
 			}
 			return
 		}
-
 		var cancel context.CancelFunc
-		{
-			ctx, cancel = context.WithCancel(ctx)
-		}
+		ctx, cancel = context.WithCancel(ctx)
 		v := &bidirectionalstreamingservice.BidirectionalStreamingMethodEndpointInput{
 			Stream: &BidirectionalStreamingMethodServerStream{
 				upgrader:   upgrader,
@@ -2148,7 +2115,6 @@ func NewBidirectionalStreamingMethodHandler(
 			Payload: payload.(*bidirectionalstreamingservice.Payload),
 		}
 		_, err = endpoint(ctx, v)
-
 		if err != nil {
 			if _, ok := err.(websocket.HandshakeError); ok {
 				return
@@ -2261,9 +2227,7 @@ func (c *Client) BidirectionalStreamingMethod() goa.Endpoint {
 			return nil, err
 		}
 		var cancel context.CancelFunc
-		{
-			ctx, cancel = context.WithCancel(ctx)
-		}
+		ctx, cancel = context.WithCancel(ctx)
 		conn, resp, err := c.dialer.DialContext(ctx, req.URL.String(), req.Header)
 		if err != nil {
 			if resp != nil {
@@ -2342,11 +2306,8 @@ func NewBidirectionalStreamingNoPayloadMethodHandler(
 		ctx = context.WithValue(ctx, goa.MethodKey, "BidirectionalStreamingNoPayloadMethod")
 		ctx = context.WithValue(ctx, goa.ServiceKey, "BidirectionalStreamingNoPayloadService")
 		var err error
-
 		var cancel context.CancelFunc
-		{
-			ctx, cancel = context.WithCancel(ctx)
-		}
+		ctx, cancel = context.WithCancel(ctx)
 		v := &bidirectionalstreamingnopayloadservice.BidirectionalStreamingNoPayloadMethodEndpointInput{
 			Stream: &BidirectionalStreamingNoPayloadMethodServerStream{
 				upgrader:   upgrader,
@@ -2357,7 +2318,6 @@ func NewBidirectionalStreamingNoPayloadMethodHandler(
 			},
 		}
 		_, err = endpoint(ctx, v)
-
 		if err != nil {
 			if _, ok := err.(websocket.HandshakeError); ok {
 				return
@@ -2402,9 +2362,7 @@ func (c *Client) BidirectionalStreamingNoPayloadMethod() goa.Endpoint {
 			return nil, err
 		}
 		var cancel context.CancelFunc
-		{
-			ctx, cancel = context.WithCancel(ctx)
-		}
+		ctx, cancel = context.WithCancel(ctx)
 		conn, resp, err := c.dialer.DialContext(ctx, req.URL.String(), req.Header)
 		if err != nil {
 			if resp != nil {
diff --git a/http/codegen/transform_helper_test.go b/http/codegen/transform_helper_test.go
index c734d1e9..eb05a543 100644
--- a/http/codegen/transform_helper_test.go
+++ b/http/codegen/transform_helper_test.go
@@ -23,7 +23,7 @@ func TestTransformHelperServer(t *testing.T) {
 	for _, c := range cases {
 		t.Run(c.Name, func(t *testing.T) {
 			RunHTTPDSL(t, c.DSL)
-			f := serverEncodeDecode("", expr.Root.API.HTTP.Services[0])
+			f := serverEncodeDecodeFile("", expr.Root.API.HTTP.Services[0])
 			sections := f.SectionTemplates
 			code := codegen.SectionCode(t, sections[len(sections)-c.Offset])
 			if code != c.Code {
@@ -48,7 +48,7 @@ func TestTransformHelperCLI(t *testing.T) {
 	for _, c := range cases {
 		t.Run(c.Name, func(t *testing.T) {
 			RunHTTPDSL(t, c.DSL)
-			f := clientEncodeDecode("", expr.Root.API.HTTP.Services[0])
+			f := clientEncodeDecodeFile("", expr.Root.API.HTTP.Services[0])
 			sections := f.SectionTemplates
 			code := codegen.SectionCode(t, sections[len(sections)-c.Offset])
 			if code != c.Code {