Repository: goadesign/goa
Pull request #2566 (2020-06-01 10:21:16)

Enable ContentType DSL for HTTP error responses
Now It seems `ContentType` DSL is disabled for HTTP error responses. This patch enables `ContentType` DSL for HTTP error responses.


Patch:
diff --git a/cmd/goa/main.go b/cmd/goa/main.go
index fcd2d0cd..b3e191b3 100644
--- a/cmd/goa/main.go
+++ b/cmd/goa/main.go
@@ -111,8 +111,8 @@ func help() {
 Learn more at https://goa.design.
 
 Usage:
-  goa gen PACKAGE [--out DIRECTORY] [--debug]
-  goa example PACKAGE [--out DIRECTORY] [--debug]
+  goa gen PACKAGE [--output DIRECTORY] [--debug]
+  goa example PACKAGE [--output DIRECTORY] [--debug]
   goa version
 
 Commands:
diff --git a/codegen/funcs.go b/codegen/funcs.go
index 52add593..fecb7c74 100644
--- a/codegen/funcs.go
+++ b/codegen/funcs.go
@@ -145,10 +145,15 @@ func CamelCase(name string, firstUpper bool, acronym bool) string {
 		// [w,i] is a word.
 		word := string(runes[w:i])
 		// is it one of our initialisms?
-		if u := strings.ToUpper(word); acronym && commonInitialisms[u] {
-			if firstUpper {
-				u = strings.ToUpper(u)
-			} else if w == 0 {
+		if u := strings.ToUpper(word); commonInitialisms[u] {
+			switch {
+			case firstUpper && acronym:
+				// u is already in upper case. Nothing to do here.
+			case firstUpper && !acronym:
+				u = strings.Title(strings.ToLower(u))
+			case w > 0 && !acronym:
+				u = strings.Title(strings.ToLower(u))
+			case w == 0:
 				u = strings.ToLower(u)
 			}
 
diff --git a/codegen/service/convert.go b/codegen/service/convert.go
index ff062b81..a70b2951 100644
--- a/codegen/service/convert.go
+++ b/codegen/service/convert.go
@@ -554,6 +554,13 @@ func attributeName(obj *expr.Object, name string) (string, string) {
 			return ln, name
 		}
 	}
+	// next look for a lower camel case without acronym
+	lcn := codegen.CamelCase(name, false, false)
+	for _, nat := range *obj {
+		if nat.Name == lcn {
+			return lcn, name
+		}
+	}
 	// finally look for a snake case representation
 	sn := codegen.SnakeCase(name)
 	for _, nat := range *obj {
diff --git a/grpc/codegen/protobuf.go b/grpc/codegen/protobuf.go
index 3a8f057a..20b03e15 100644
--- a/grpc/codegen/protobuf.go
+++ b/grpc/codegen/protobuf.go
@@ -107,12 +107,12 @@ func makeProtoBufMessageR(att *expr.AttributeExpr, tname *string, sd *ServiceDat
 		switch {
 		case expr.IsArray(att.Type):
 			wrapAttr(att, "ArrayOf"+tname+
-				protoBufify(protoBufMessageDef(expr.AsArray(att.Type).ElemType, sd), true), sd)
+				protoBufify(protoBufMessageDef(expr.AsArray(att.Type).ElemType, sd), true, true), sd)
 		case expr.IsMap(att.Type):
 			m := expr.AsMap(att.Type)
 			wrapAttr(att, tname+"MapOf"+
-				protoBufify(protoBufMessageDef(m.KeyType, sd), true)+
-				protoBufify(protoBufMessageDef(m.ElemType, sd), true), sd)
+				protoBufify(protoBufMessageDef(m.KeyType, sd), true, true)+
+				protoBufify(protoBufMessageDef(m.ElemType, sd), true, true), sd)
 		}
 	}
 
@@ -190,7 +190,7 @@ func protoBufMessageName(att *expr.AttributeExpr, s *codegen.NameScope) string {
 func protoBufFullMessageName(att *expr.AttributeExpr, pkg string, s *codegen.NameScope) string {
 	switch actual := att.Type.(type) {
 	case expr.UserType:
-		n := s.HashedUnique(actual, protoBufify(actual.Name(), true), "")
+		n := s.HashedUnique(actual, protoBufify(actual.Name(), true, true), "")
 		if pkg == "" {
 			return n
 		}
@@ -257,7 +257,7 @@ func protoBufMessageDef(att *expr.AttributeExpr, sd *ServiceData) string {
 				desc string
 			)
 			{
-				fn = codegen.SnakeCase(protoBufify(nat.Name, false))
+				fn = codegen.SnakeCase(protoBufify(nat.Name, false, false))
 				fnum = rpcTag(nat.Attribute)
 				if prim := getPrimitive(nat.Attribute); prim != nil {
 					typ = protoBufMessageDef(prim, sd)
@@ -295,7 +295,7 @@ func protoBufGoFullTypeRef(att *expr.AttributeExpr, pkg string, s *codegen.NameS
 //
 // If firstUpper is true the first character of the identifier is uppercase
 // otherwise it's lowercase.
-func protoBufify(str string, firstUpper bool) string {
+func protoBufify(str string, firstUpper, acronym bool) string {
 	// Optimize trivial case
 	if str == "" {
 		return ""
@@ -308,8 +308,7 @@ func protoBufify(str string, firstUpper bool) string {
 		str = str[:idx]
 	}
 
-	// We must disable acronyms to generate gRPC compatible names.
-	str = codegen.CamelCase(str, firstUpper, false)
+	str = codegen.CamelCase(str, firstUpper, acronym)
 	if str == "" {
 		// All characters are invalid. Produce a default value.
 		if firstUpper {
@@ -329,7 +328,7 @@ func protoBufifyAtt(att *expr.AttributeExpr, name string, upper bool) string {
 			name = tname[0]
 		}
 	}
-	return protoBufify(name, upper)
+	return protoBufify(name, upper, false)
 }
 
 // protoBufNativeMessageTypeName returns the protocol buffer built-in type
diff --git a/grpc/codegen/service_data.go b/grpc/codegen/service_data.go
index e5963672..bf3b5d35 100644
--- a/grpc/codegen/service_data.go
+++ b/grpc/codegen/service_data.go
@@ -451,16 +451,16 @@ func (d ServicesData) analyze(gs *expr.GRPCServiceExpr) *ServiceData {
 	}
 	for _, e := range gs.GRPCEndpoints {
 		// convert request and response types to protocol buffer message types
-		e.Request = makeProtoBufMessage(e.Request, protoBufify(e.Name()+"_request", true), sd)
+		e.Request = makeProtoBufMessage(e.Request, protoBufify(e.Name()+"_request", true, true), sd)
 		if e.MethodExpr.StreamingPayload.Type != expr.Empty {
-			e.StreamingRequest = makeProtoBufMessage(e.StreamingRequest, protoBufify(e.Name()+"_streaming_request", true), sd)
+			e.StreamingRequest = makeProtoBufMessage(e.StreamingRequest, protoBufify(e.Name()+"_streaming_request", true, true), sd)
 		}
-		e.Response.Message = makeProtoBufMessage(e.Response.Message, protoBufify(e.Name()+"_response", true), sd)
+		e.Response.Message = makeProtoBufMessage(e.Response.Message, protoBufify(e.Name()+"_response", true, true), sd)
 		for _, er := range e.GRPCErrors {
 			if er.ErrorExpr.Type == expr.ErrorResult || !expr.IsObject(er.ErrorExpr.Type) {
 				continue
 			}
-			er.Response.Message = makeProtoBufMessage(er.Response.Message, protoBufify(e.Name()+"_"+er.Name+"_error", true), sd)
+			er.Response.Message = makeProtoBufMessage(er.Response.Message, protoBufify(e.Name()+"_"+er.Name+"_error", true, true), sd)
 		}
 
 		// collect all the nested messages and return the top-level message
diff --git a/http/codegen/server.go b/http/codegen/server.go
index 6d2afe92..b3b74226 100644
--- a/http/codegen/server.go
+++ b/http/codegen/server.go
@@ -1102,6 +1102,9 @@ func {{ .ErrorEncoder }}(encoder func(context.Context, http.ResponseWriter) goah
 		case {{ printf "%q" .Name }}:
 			res := v.({{ $err.Ref }})
 			{{- with .Response}}
+				{{- if .ContentType }}
+					ctx = context.WithValue(ctx, goahttp.ContentTypeKey, "{{ .ContentType }}")
+				{{- end }}
 				{{- template "response" . }}
 				{{- if .ServerBody }}
 				return enc.Encode(body)
diff --git a/http/codegen/service_data.go b/http/codegen/service_data.go
index 215737d7..f7ea71d5 100644
--- a/http/codegen/service_data.go
+++ b/http/codegen/service_data.go
@@ -1806,9 +1806,14 @@ func buildErrorsData(e *expr.HTTPEndpointExpr, sd *ServiceData) []*ErrorGroupDat
 					}
 				}
 			}
+			var contentType string
+			if v.Response.ContentType != expr.ErrorResultIdentifier {
+				contentType = v.Response.ContentType
+			}
 			responseData = &ResponseData{
 				StatusCode:   statusCodeToHTTPConst(v.Response.StatusCode),
 				Headers:      headers,
+				ContentType:  contentType,
 				ErrorHeader:  v.Name,
 				ServerBody:   serverBodyData,
 				ClientBody:   clientBodyData,


Test patch:
diff --git a/codegen/funcs_test.go b/codegen/funcs_test.go
index 7b8f5bbc..0be4c956 100644
--- a/codegen/funcs_test.go
+++ b/codegen/funcs_test.go
@@ -36,26 +36,34 @@ func TestSnakeCase(t *testing.T) {
 
 func TestCamelCase(t *testing.T) {
 	cases := map[string]struct {
-		str         string
-		firstUpper  bool
-		useAcronyum bool
-		expected    string
+		str        string
+		firstUpper bool
+		useAcronym bool
+		expected   string
 	}{
-		"all lower":             {"aaa", false, true, "aaa"},
-		"all lower first upper": {"aaa", true, true, "Aaa"},
-		"start upper":           {"Aaa", false, true, "aaa"},
-		"mid upper":             {"a_aa", false, true, "aAa"},
-		"end upper":             {"aa_a", false, true, "aaA"},
-		"sequential uppers":     {"aa_aaaa", false, true, "aaAaaa"},
-		"end sequential uppers": {"aa_aa", false, true, "aaAa"},
-		"multiple_uppers":       {"aa_aaa_aaa", false, true, "aaAaaAaa"},
-		"underscores":           {"aa_aaa_aaa", false, true, "aaAaaAaa"},
-		"acronym":               {"aa_id", false, true, "aaID"},
-		"disable acronym":       {"aa_id", false, false, "aaId"},
+		"all lower":                     {"aaa", false, true, "aaa"},
+		"all lower first upper":         {"aaa", true, true, "Aaa"},
+		"start upper":                   {"Aaa", false, true, "aaa"},
+		"mid upper":                     {"a_aa", false, true, "aAa"},
+		"end upper":                     {"aa_a", false, true, "aaA"},
+		"sequential uppers":             {"aa_aaaa", false, true, "aaAaaa"},
+		"end sequential uppers":         {"aa_aa", false, true, "aaAa"},
+		"multiple_uppers":               {"aa_aaa_aaa", false, true, "aaAaaAaa"},
+		"underscores":                   {"aa_aaa_aaa", false, true, "aaAaaAaa"},
+		"acronym":                       {"aa_id", false, true, "aaID"},
+		"lower camel case":              {"aa_id", false, false, "aaId"},
+		"upper camel case":              {"aaID", false, true, "aaID"},
+		"lower camel case with acronym": {"aaId", false, true, "aaID"},
+
+		"disable acronym":                    {"aa_id", false, false, "aaId"},
+		"disable acronym first upper":        {"aaID", true, false, "AaId"},
+		"disable acronym upper case acronym": {"aa_ID", false, false, "aaId"},
+		"disable acronym upper camel case":   {"aaID", false, false, "aaId"},
+		"disable acronym lower camel case":   {"aaId", false, false, "aaId"},
 	}
 	for k, tc := range cases {
 		t.Run(k, func(t *testing.T) {
-			actual := CamelCase(tc.str, tc.firstUpper, tc.useAcronyum)
+			actual := CamelCase(tc.str, tc.firstUpper, tc.useAcronym)
 			if actual != tc.expected {
 				t.Errorf("got %q, expected %q", actual, tc.expected)
 			}
diff --git a/codegen/service/convert_test.go b/codegen/service/convert_test.go
index 8fe82f77..ab4d42c7 100644
--- a/codegen/service/convert_test.go
+++ b/codegen/service/convert_test.go
@@ -246,6 +246,7 @@ func TestConvertFile(t *testing.T) {
 		{"create-object-extra", testdata.CreateObjectExtraDSL, 1, testdata.CreateObjectExtraCode},
 		{"create-external-convert", testdata.CreateExternalDSL, 0, testdata.CreateExternalConvert},
 		{"create-alias-convert", testdata.CreateAliasDSL, 0, testdata.CreateAliasConvert},
+		{"mixed-case-convert", testdata.MixedCaseDSL, 0, testdata.MixedCaseConvert},
 	}
 	for _, c := range cases {
 		t.Run(c.Name, func(t *testing.T) {
diff --git a/codegen/service/testdata/create_dsls.go b/codegen/service/testdata/create_dsls.go
index 3542ac69..4fb2a428 100644
--- a/codegen/service/testdata/create_dsls.go
+++ b/codegen/service/testdata/create_dsls.go
@@ -248,3 +248,18 @@ var CreateAliasDSL = func() {
 		})
 	})
 }
+
+var MixedCaseDSL = func() {
+	var StringType = Type("StringType", func() {
+		CreateFrom(external.MixedCaseModel{})
+		Attribute("lowerCamelId", String)
+		Attribute("UpperCamelID", String)
+		Attribute("snake_id", String)
+	})
+
+	Service("Service", func() {
+		Method("Method", func() {
+			Payload(StringType)
+		})
+	})
+}
diff --git a/codegen/service/testdata/create_functions.go b/codegen/service/testdata/create_functions.go
index 1dfa0a83..1aa5e005 100644
--- a/codegen/service/testdata/create_functions.go
+++ b/codegen/service/testdata/create_functions.go
@@ -149,3 +149,25 @@ func (t *StringType) CreateFromConvertModel(v *aliasd.ConvertModel) {
 	*t = *temp
 }
 `
+
+var MixedCaseConvert = `// Service service type conversion functions
+//
+// Command:
+// $ goa
+
+package service
+
+import (
+	external "goa.design/goa/v3/codegen/service/testdata/external"
+)
+
+// CreateFromMixedCaseModel initializes t from the fields of v
+func (t *StringType) CreateFromMixedCaseModel(v *external.MixedCaseModel) {
+	temp := &StringType{
+		LowerCamelID: &v.LowerCamelID,
+		UpperCamelID: &v.UpperCamelID,
+		SnakeID:      &v.SnakeID,
+	}
+	*t = *temp
+}
+`
diff --git a/codegen/service/testdata/external/external.go b/codegen/service/testdata/external/external.go
index 03961783..88b8285e 100644
--- a/codegen/service/testdata/external/external.go
+++ b/codegen/service/testdata/external/external.go
@@ -3,3 +3,9 @@ package external
 type ConvertModel struct {
 	Foo string
 }
+
+type MixedCaseModel struct {
+	LowerCamelID string
+	UpperCamelID string
+	SnakeID      string
+}
diff --git a/grpc/codegen/testdata/streaming_code.go b/grpc/codegen/testdata/streaming_code.go
index a6e43132..2b7068ac 100644
--- a/grpc/codegen/testdata/streaming_code.go
+++ b/grpc/codegen/testdata/streaming_code.go
@@ -328,7 +328,7 @@ func (s *MethodBidirectionalStreamingRPCClientStream) Recv() (*servicebidirectio
 	if err != nil {
 		return res, err
 	}
-	proj := NewIdView(v)
+	proj := NewIDView(v)
 	vres := &servicebidirectionalstreamingrpcviews.ID{Projected: proj, View: "default"}
 	return servicebidirectionalstreamingrpc.NewID(vres), nil
 }
diff --git a/http/codegen/server_error_encoder_test.go b/http/codegen/server_error_encoder_test.go
index e479f0b5..bf070e09 100644
--- a/http/codegen/server_error_encoder_test.go
+++ b/http/codegen/server_error_encoder_test.go
@@ -16,10 +16,14 @@ func TestEncodeError(t *testing.T) {
 	}{
 		{"primitive-error-response", testdata.PrimitiveErrorResponseDSL, testdata.PrimitiveErrorResponseEncoderCode},
 		{"default-error-response", testdata.DefaultErrorResponseDSL, testdata.DefaultErrorResponseEncoderCode},
+		{"default-error-response-with-content-type", testdata.DefaultErrorResponseWithContentTypeDSL, testdata.DefaultErrorResponseWithContentTypeEncoderCode},
 		{"service-error-response", testdata.ServiceErrorResponseDSL, testdata.ServiceErrorResponseEncoderCode},
 		{"api-error-response", testdata.APIErrorResponseDSL, testdata.ServiceErrorResponseEncoderCode},
+		{"api-error-response-with-content-type", testdata.APIErrorResponseWithContentTypeDSL, testdata.ServiceErrorResponseWithContentTypeEncoderCode},
 		{"no-body-error-response", testdata.NoBodyErrorResponseDSL, testdata.NoBodyErrorResponseEncoderCode},
+		{"no-body-error-response-with-content-type", testdata.NoBodyErrorResponseWithContentTypeDSL, testdata.NoBodyErrorResponseWithContentTypeEncoderCode},
 		{"api-no-body-error-response", testdata.APINoBodyErrorResponseDSL, testdata.NoBodyErrorResponseEncoderCode},
+		{"api-no-body-error-response-with-content-type", testdata.APINoBodyErrorResponseWithContentTypeDSL, testdata.NoBodyErrorResponseWithContentTypeEncoderCode},
 	}
 	for _, c := range cases {
 		t.Run(c.Name, func(t *testing.T) {
diff --git a/http/codegen/testdata/error_encoder_code.go b/http/codegen/testdata/error_encoder_code.go
index e93144bb..d11d2484 100644
--- a/http/codegen/testdata/error_encoder_code.go
+++ b/http/codegen/testdata/error_encoder_code.go
@@ -71,6 +71,36 @@ func EncodeMethodDefaultErrorResponseError(encoder func(context.Context, http.Re
 }
 `
 
+var DefaultErrorResponseWithContentTypeEncoderCode = `// EncodeMethodDefaultErrorResponseError returns an encoder for errors returned
+// by the MethodDefaultErrorResponse ServiceDefaultErrorResponse endpoint.
+func EncodeMethodDefaultErrorResponseError(encoder func(context.Context, http.ResponseWriter) goahttp.Encoder, formatter func(err error) goahttp.Statuser) func(context.Context, http.ResponseWriter, error) error {
+	encodeError := goahttp.ErrorEncoder(encoder, formatter)
+	return func(ctx context.Context, w http.ResponseWriter, v error) error {
+		en, ok := v.(ErrorNamer)
+		if !ok {
+			return encodeError(ctx, w, v)
+		}
+		switch en.ErrorName() {
+		case "bad_request":
+			res := v.(*goa.ServiceError)
+			ctx = context.WithValue(ctx, goahttp.ContentTypeKey, "application/xml")
+			enc := encoder(ctx, w)
+			var body interface{}
+			if formatter != nil {
+				body = formatter(res)
+			} else {
+				body = NewMethodDefaultErrorResponseBadRequestResponseBody(res)
+			}
+			w.Header().Set("goa-error", "bad_request")
+			w.WriteHeader(http.StatusBadRequest)
+			return enc.Encode(body)
+		default:
+			return encodeError(ctx, w, v)
+		}
+	}
+}
+`
+
 var ServiceErrorResponseEncoderCode = `// EncodeMethodServiceErrorResponseError returns an encoder for errors returned
 // by the MethodServiceErrorResponse ServiceServiceErrorResponse endpoint.
 func EncodeMethodServiceErrorResponseError(encoder func(context.Context, http.ResponseWriter) goahttp.Encoder, formatter func(err error) goahttp.Statuser) func(context.Context, http.ResponseWriter, error) error {
@@ -112,6 +142,48 @@ func EncodeMethodServiceErrorResponseError(encoder func(context.Context, http.Re
 }
 `
 
+var ServiceErrorResponseWithContentTypeEncoderCode = `// EncodeMethodServiceErrorResponseError returns an encoder for errors returned
+// by the MethodServiceErrorResponse ServiceServiceErrorResponse endpoint.
+func EncodeMethodServiceErrorResponseError(encoder func(context.Context, http.ResponseWriter) goahttp.Encoder, formatter func(err error) goahttp.Statuser) func(context.Context, http.ResponseWriter, error) error {
+	encodeError := goahttp.ErrorEncoder(encoder, formatter)
+	return func(ctx context.Context, w http.ResponseWriter, v error) error {
+		en, ok := v.(ErrorNamer)
+		if !ok {
+			return encodeError(ctx, w, v)
+		}
+		switch en.ErrorName() {
+		case "internal_error":
+			res := v.(*goa.ServiceError)
+			enc := encoder(ctx, w)
+			var body interface{}
+			if formatter != nil {
+				body = formatter(res)
+			} else {
+				body = NewMethodServiceErrorResponseInternalErrorResponseBody(res)
+			}
+			w.Header().Set("goa-error", "internal_error")
+			w.WriteHeader(http.StatusInternalServerError)
+			return enc.Encode(body)
+		case "bad_request":
+			res := v.(*goa.ServiceError)
+			ctx = context.WithValue(ctx, goahttp.ContentTypeKey, "application/xml")
+			enc := encoder(ctx, w)
+			var body interface{}
+			if formatter != nil {
+				body = formatter(res)
+			} else {
+				body = NewMethodServiceErrorResponseBadRequestResponseBody(res)
+			}
+			w.Header().Set("goa-error", "bad_request")
+			w.WriteHeader(http.StatusBadRequest)
+			return enc.Encode(body)
+		default:
+			return encodeError(ctx, w, v)
+		}
+	}
+}
+`
+
 var NoBodyErrorResponseEncoderCode = `// EncodeMethodServiceErrorResponseError returns an encoder for errors returned
 // by the MethodServiceErrorResponse ServiceNoBodyErrorResponse endpoint.
 func EncodeMethodServiceErrorResponseError(encoder func(context.Context, http.ResponseWriter) goahttp.Encoder, formatter func(err error) goahttp.Statuser) func(context.Context, http.ResponseWriter, error) error {
@@ -136,3 +208,29 @@ func EncodeMethodServiceErrorResponseError(encoder func(context.Context, http.Re
 	}
 }
 `
+
+var NoBodyErrorResponseWithContentTypeEncoderCode = `// EncodeMethodServiceErrorResponseError returns an encoder for errors returned
+// by the MethodServiceErrorResponse ServiceNoBodyErrorResponse endpoint.
+func EncodeMethodServiceErrorResponseError(encoder func(context.Context, http.ResponseWriter) goahttp.Encoder, formatter func(err error) goahttp.Statuser) func(context.Context, http.ResponseWriter, error) error {
+	encodeError := goahttp.ErrorEncoder(encoder, formatter)
+	return func(ctx context.Context, w http.ResponseWriter, v error) error {
+		en, ok := v.(ErrorNamer)
+		if !ok {
+			return encodeError(ctx, w, v)
+		}
+		switch en.ErrorName() {
+		case "bad_request":
+			res := v.(*servicenobodyerrorresponse.StringError)
+			ctx = context.WithValue(ctx, goahttp.ContentTypeKey, "application/xml")
+			if res.Header != nil {
+				w.Header().Set("Header", *res.Header)
+			}
+			w.Header().Set("goa-error", "bad_request")
+			w.WriteHeader(http.StatusBadRequest)
+			return nil
+		default:
+			return encodeError(ctx, w, v)
+		}
+	}
+}
+`
diff --git a/http/codegen/testdata/error_response_dsls.go b/http/codegen/testdata/error_response_dsls.go
index ac531d08..08842133 100644
--- a/http/codegen/testdata/error_response_dsls.go
+++ b/http/codegen/testdata/error_response_dsls.go
@@ -16,6 +16,20 @@ var DefaultErrorResponseDSL = func() {
 	})
 }
 
+var DefaultErrorResponseWithContentTypeDSL = func() {
+	Service("ServiceDefaultErrorResponse", func() {
+		Method("MethodDefaultErrorResponse", func() {
+			Error("bad_request")
+			HTTP(func() {
+				GET("/one/two")
+				Response("bad_request", StatusBadRequest, func() {
+					ContentType("application/xml")
+				})
+			})
+		})
+	})
+}
+
 var PrimitiveErrorResponseDSL = func() {
 	Service("ServicePrimitiveErrorResponse", func() {
 		Method("MethodPrimitiveErrorResponse", func() {
@@ -65,6 +79,27 @@ var APIErrorResponseDSL = func() {
 	})
 }
 
+var APIErrorResponseWithContentTypeDSL = func() {
+	var _ = API("test", func() {
+		Error("bad_request")
+		HTTP(func() {
+			Response(StatusBadRequest, "bad_request", func() {
+				ContentType("application/xml")
+			})
+		})
+	})
+	Service("ServiceServiceErrorResponse", func() {
+		Method("MethodServiceErrorResponse", func() {
+			Error("bad_request")
+			Error("internal_error")
+			HTTP(func() {
+				GET("/one/two")
+				Response("internal_error", StatusInternalServerError)
+			})
+		})
+	})
+}
+
 var APINoBodyErrorResponseDSL = func() {
 	var StringError = Type("StringError", func() { Attribute("header") })
 	var _ = API("test", func() {
@@ -85,6 +120,29 @@ var APINoBodyErrorResponseDSL = func() {
 	})
 }
 
+var APINoBodyErrorResponseWithContentTypeDSL = func() {
+	var StringError = ResultType("application/vnd.string.error", func() {
+		ContentType("application/xml")
+		Attribute("header")
+	})
+	var _ = API("test", func() {
+		Error("bad_request", StringError)
+		HTTP(func() {
+			Response("bad_request", StatusBadRequest, func() {
+				Header("header")
+			})
+		})
+	})
+	Service("ServiceNoBodyErrorResponse", func() {
+		Error("bad_request")
+		Method("MethodServiceErrorResponse", func() {
+			HTTP(func() {
+				GET("/one/two")
+			})
+		})
+	})
+}
+
 var NoBodyErrorResponseDSL = func() {
 	var StringError = Type("StringError", func() { Attribute("header") })
 	Service("ServiceNoBodyErrorResponse", func() {
@@ -101,3 +159,23 @@ var NoBodyErrorResponseDSL = func() {
 		})
 	})
 }
+
+var NoBodyErrorResponseWithContentTypeDSL = func() {
+	var StringError = ResultType("application/vnd.string.error", func() {
+		ContentType("application/xml")
+		Attribute("header")
+	})
+	Service("ServiceNoBodyErrorResponse", func() {
+		Error("bad_request", StringError)
+		HTTP(func() {
+			Response("bad_request", StatusBadRequest, func() {
+				Header("header")
+			})
+		})
+		Method("MethodServiceErrorResponse", func() {
+			HTTP(func() {
+				GET("/one/two")
+			})
+		})
+	})
+}