Skip to content

Commit 8aed3dd

Browse files
authored
Generate validation code for required attributes in inline struct http bodies (#3580)
* Split test cases for Required * Generate validation code for required attributes in inline struct http bodies.
1 parent 381d088 commit 8aed3dd

File tree

4 files changed

+118
-7
lines changed

4 files changed

+118
-7
lines changed

http/codegen/server_decode_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ func TestDecode(t *testing.T) {
151151
{"decode-body-user-nested", testdata.PayloadBodyNestedUserDSL, testdata.PayloadBodyNestedUserDecodeCode},
152152
{"decode-body-user-validate", testdata.PayloadBodyUserValidateDSL, testdata.PayloadBodyUserValidateDecodeCode},
153153
{"decode-body-object", testdata.PayloadBodyObjectDSL, testdata.PayloadBodyObjectDecodeCode},
154+
{"decode-body-object-required", testdata.PayloadBodyObjectRequiredDSL, testdata.PayloadBodyObjectRequiredDecodeCode},
154155
{"decode-body-object-validate", testdata.PayloadBodyObjectValidateDSL, testdata.PayloadBodyObjectValidateDecodeCode},
155156
{"decode-body-union", testdata.PayloadBodyUnionDSL, testdata.PayloadBodyUnionDecodeCode},
156157
{"decode-body-union-validate", testdata.PayloadBodyUnionValidateDSL, testdata.PayloadBodyUnionValidateDecodeCode},
@@ -170,6 +171,7 @@ func TestDecode(t *testing.T) {
170171
{"decode-body-primitive-array-string-validate", testdata.PayloadBodyPrimitiveArrayStringValidateDSL, testdata.PayloadBodyPrimitiveArrayStringValidateDecodeCode},
171172
{"decode-body-primitive-array-bool-validate", testdata.PayloadBodyPrimitiveArrayBoolValidateDSL, testdata.PayloadBodyPrimitiveArrayBoolValidateDecodeCode},
172173

174+
{"decode-body-primitive-array-user-required", testdata.PayloadBodyPrimitiveArrayUserRequiredDSL, testdata.PayloadBodyPrimitiveArrayUserRequiredDecodeCode},
173175
{"decode-body-primitive-array-user-validate", testdata.PayloadBodyPrimitiveArrayUserValidateDSL, testdata.PayloadBodyPrimitiveArrayUserValidateDecodeCode},
174176
{"decode-body-primitive-field-array-user", testdata.PayloadBodyPrimitiveFieldArrayUserDSL, testdata.PayloadBodyPrimitiveFieldArrayUserDecodeCode},
175177
{"decode-body-extend-primitive-field-array-user", testdata.PayloadExtendBodyPrimitiveFieldArrayUserDSL, testdata.PayloadBodyPrimitiveFieldArrayUserDecodeCode},

http/codegen/service_data.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1992,6 +1992,9 @@ func buildRequestBodyType(body, att *expr.AttributeExpr, e *expr.HTTPEndpointExp
19921992
}
19931993
}
19941994
} else {
1995+
// Generate validation code first because inline struct validation is removed.
1996+
ctx := codegen.NewAttributeContext(!expr.IsPrimitive(body.Type), false, !svr, "", sd.Scope)
1997+
validateRef = codegen.ValidationCode(body, nil, ctx, true, expr.IsAlias(body.Type), false, "body")
19951998
if svr && expr.IsObject(body.Type) {
19961999
// Body is an explicit object described in the design and in
19972000
// this case the GoTypeRef is an inline struct definition. We
@@ -2000,8 +2003,6 @@ func buildRequestBodyType(body, att *expr.AttributeExpr, e *expr.HTTPEndpointExp
20002003
body.Validation = nil
20012004
}
20022005
varname = sd.Scope.GoTypeRef(body)
2003-
ctx := codegen.NewAttributeContext(false, false, !svr, "", sd.Scope)
2004-
validateRef = codegen.ValidationCode(body, nil, ctx, true, expr.IsAlias(body.Type), false, "body")
20052006
desc = body.Description
20062007
}
20072008
var init *InitData

http/codegen/testdata/payload_decode_functions.go

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3917,6 +3917,40 @@ func DecodeMethodBodyObjectRequest(mux goahttp.Muxer, decoder func(*http.Request
39173917
}
39183918
`
39193919

3920+
var PayloadBodyObjectRequiredDecodeCode = `// DecodeMethodBodyObjectRequiredRequest returns a decoder for requests sent to
3921+
// the ServiceBodyObjectRequired MethodBodyObjectRequired endpoint.
3922+
func DecodeMethodBodyObjectRequiredRequest(mux goahttp.Muxer, decoder func(*http.Request) goahttp.Decoder) func(*http.Request) (any, error) {
3923+
return func(r *http.Request) (any, error) {
3924+
var (
3925+
body struct {
3926+
B *string ` + "`" + `form:"b" json:"b" xml:"b"` + "`" + `
3927+
}
3928+
err error
3929+
)
3930+
err = decoder(r).Decode(&body)
3931+
if err != nil {
3932+
if err == io.EOF {
3933+
return nil, goa.MissingPayloadError()
3934+
}
3935+
var gerr *goa.ServiceError
3936+
if errors.As(err, &gerr) {
3937+
return nil, gerr
3938+
}
3939+
return nil, goa.DecodePayloadError(err.Error())
3940+
}
3941+
if body.B == nil {
3942+
err = goa.MergeErrors(err, goa.MissingFieldError("b", "body"))
3943+
}
3944+
if err != nil {
3945+
return nil, err
3946+
}
3947+
payload := NewMethodBodyObjectRequiredPayload(body)
3948+
3949+
return payload, nil
3950+
}
3951+
}
3952+
`
3953+
39203954
var PayloadBodyObjectValidateDecodeCode = `// DecodeMethodBodyObjectValidateRequest returns a decoder for requests sent to
39213955
// the ServiceBodyObjectValidate MethodBodyObjectValidate endpoint.
39223956
func DecodeMethodBodyObjectValidateRequest(mux goahttp.Muxer, decoder func(*http.Request) goahttp.Decoder) func(*http.Request) (any, error) {
@@ -3938,6 +3972,12 @@ func DecodeMethodBodyObjectValidateRequest(mux goahttp.Muxer, decoder func(*http
39383972
}
39393973
return nil, goa.DecodePayloadError(err.Error())
39403974
}
3975+
if body.B != nil {
3976+
err = goa.MergeErrors(err, goa.ValidatePattern("body.b", *body.B, "pattern"))
3977+
}
3978+
if err != nil {
3979+
return nil, err
3980+
}
39413981
payload := NewMethodBodyObjectValidatePayload(body)
39423982
39433983
return payload, nil
@@ -4440,6 +4480,43 @@ func DecodeMethodBodyPrimitiveArrayBoolValidateRequest(mux goahttp.Muxer, decode
44404480
}
44414481
`
44424482

4483+
var PayloadBodyPrimitiveArrayUserRequiredDecodeCode = `// DecodeMethodBodyPrimitiveArrayUserRequiredRequest returns a decoder for
4484+
// requests sent to the ServiceBodyPrimitiveArrayUserRequired
4485+
// MethodBodyPrimitiveArrayUserRequired endpoint.
4486+
func DecodeMethodBodyPrimitiveArrayUserRequiredRequest(mux goahttp.Muxer, decoder func(*http.Request) goahttp.Decoder) func(*http.Request) (any, error) {
4487+
return func(r *http.Request) (any, error) {
4488+
var (
4489+
body []*PayloadTypeRequestBody
4490+
err error
4491+
)
4492+
err = decoder(r).Decode(&body)
4493+
if err != nil {
4494+
if err == io.EOF {
4495+
return nil, goa.MissingPayloadError()
4496+
}
4497+
var gerr *goa.ServiceError
4498+
if errors.As(err, &gerr) {
4499+
return nil, gerr
4500+
}
4501+
return nil, goa.DecodePayloadError(err.Error())
4502+
}
4503+
for _, e := range body {
4504+
if e != nil {
4505+
if err2 := ValidatePayloadTypeRequestBody(e); err2 != nil {
4506+
err = goa.MergeErrors(err, err2)
4507+
}
4508+
}
4509+
}
4510+
if err != nil {
4511+
return nil, err
4512+
}
4513+
payload := NewMethodBodyPrimitiveArrayUserRequiredPayloadType(body)
4514+
4515+
return payload, nil
4516+
}
4517+
}
4518+
`
4519+
44434520
var PayloadBodyPrimitiveArrayUserValidateDecodeCode = `// DecodeMethodBodyPrimitiveArrayUserValidateRequest returns a decoder for
44444521
// requests sent to the ServiceBodyPrimitiveArrayUserValidate
44454522
// MethodBodyPrimitiveArrayUserValidate endpoint.

http/codegen/testdata/payload_dsls.go

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1947,7 +1947,6 @@ var PayloadBodyStringValidateDSL = func() {
19471947
Attribute("b", String, func() {
19481948
Pattern("pattern")
19491949
})
1950-
Required("b")
19511950
})
19521951
HTTP(func() {
19531952
POST("/")
@@ -2039,9 +2038,9 @@ var PayloadBodyObjectDSL = func() {
20392038
})
20402039
}
20412040

2042-
var PayloadBodyObjectValidateDSL = func() {
2043-
Service("ServiceBodyObjectValidate", func() {
2044-
Method("MethodBodyObjectValidate", func() {
2041+
var PayloadBodyObjectRequiredDSL = func() {
2042+
Service("ServiceBodyObjectRequired", func() {
2043+
Method("MethodBodyObjectRequired", func() {
20452044
Payload(func() {
20462045
Attribute("b", String)
20472046
Required("b")
@@ -2057,6 +2056,24 @@ var PayloadBodyObjectValidateDSL = func() {
20572056
})
20582057
}
20592058

2059+
var PayloadBodyObjectValidateDSL = func() {
2060+
Service("ServiceBodyObjectValidate", func() {
2061+
Method("MethodBodyObjectValidate", func() {
2062+
Payload(func() {
2063+
Attribute("b", String, func() {
2064+
Pattern("pattern")
2065+
})
2066+
})
2067+
HTTP(func() {
2068+
POST("/")
2069+
Body(func() {
2070+
Attribute("b", String)
2071+
})
2072+
})
2073+
})
2074+
})
2075+
}
2076+
20602077
var PayloadBodyUnionDSL = func() {
20612078
var Union = Type("Union", func() {
20622079
OneOf("Values", func() {
@@ -2342,12 +2359,26 @@ var PayloadBodyPrimitiveArrayBoolValidateDSL = func() {
23422359
})
23432360
}
23442361

2362+
var PayloadBodyPrimitiveArrayUserRequiredDSL = func() {
2363+
var PayloadType = Type("PayloadType", func() {
2364+
Attribute("a", String)
2365+
Required("a")
2366+
})
2367+
Service("ServiceBodyPrimitiveArrayUserRequired", func() {
2368+
Method("MethodBodyPrimitiveArrayUserRequired", func() {
2369+
Payload(ArrayOf(PayloadType))
2370+
HTTP(func() {
2371+
POST("/")
2372+
})
2373+
})
2374+
})
2375+
}
2376+
23452377
var PayloadBodyPrimitiveArrayUserValidateDSL = func() {
23462378
var PayloadType = Type("PayloadType", func() {
23472379
Attribute("a", String, func() {
23482380
Pattern("pattern")
23492381
})
2350-
Required("a")
23512382
})
23522383
Service("ServiceBodyPrimitiveArrayUserValidate", func() {
23532384
Method("MethodBodyPrimitiveArrayUserValidate", func() {

0 commit comments

Comments
 (0)