Repository: goadesign/goa
Pull request #2434 (2019-12-15 14:48:45)

Fix a bug that required is not inherited by Parent DSL
see. #2429

ikawaha: Thank you for your suggestion!
raphael: Looks great, thank you!

Patch:
diff --git a/expr/http_endpoint.go b/expr/http_endpoint.go
index f1c53818..6bcd0359 100644
--- a/expr/http_endpoint.go
+++ b/expr/http_endpoint.go
@@ -192,18 +192,23 @@ func (e *HTTPEndpointExpr) Prepare() {
 			c.Prepare()
 			if !e.HasAbsoluteRoutes() {
 				headers.Merge(c.Headers)
-				params.Merge(c.PathParams())
+				cpp := c.PathParams()
+				params.Merge(cpp)
 
 				// Inherit attributes for path params from parent service
-				WalkMappedAttr(c.PathParams(), func(name, _ string, _ *AttributeExpr) error {
+				WalkMappedAttr(cpp, func(name, _ string, _ *AttributeExpr) error {
 					if att := c.MethodExpr.Payload.Find(name); att != nil {
 						if e.MethodExpr.Payload.Type == Empty {
 							e.MethodExpr.Payload.Type = &Object{}
 						}
-						if o := AsObject(e.MethodExpr.Payload.Type); o != nil {
-							if o.Attribute(name) == nil {
-								o.Set(name, att)
+						if o := AsObject(e.MethodExpr.Payload.Type); o != nil && o.Attribute(name) == nil {
+							if c.MethodExpr.Payload.IsRequired(name) {
+								if e.MethodExpr.Payload.Validation == nil {
+									e.MethodExpr.Payload.Validation = &ValidationExpr{}
+								}
+								e.MethodExpr.Payload.Validation.AddRequired(name)
 							}
+							o.Set(name, att)
 						}
 					}
 					return nil


Test patch:
diff --git a/expr/http_endpoint_test.go b/expr/http_endpoint_test.go
index e9d1483a..7b9e3a55 100644
--- a/expr/http_endpoint_test.go
+++ b/expr/http_endpoint_test.go
@@ -168,6 +168,24 @@ func TestHTTPEndpointValidation(t *testing.T) {
 	}
 }
 
+func TestHTTPEndpointParentRequired(t *testing.T) {
+	root := expr.RunDSL(t, testdata.EndpointHasParent)
+	svc := root.Service("Child")
+	if svc == nil {
+		t.Fatal(`unexpected error, service "Child" not found`)
+	}
+	m := svc.Method("Method")
+	if m == nil {
+		t.Fatal(`unexpected error, method "Method" not found`)
+	}
+	if !m.Payload.IsRequired("ancestor_id") {
+		t.Errorf(`expected "ancestor_id" is required, but not so`)
+	}
+	if !m.Payload.IsRequired("parent_id") {
+		t.Errorf(`expected "parent_id" is required, but not so`)
+	}
+}
+
 func TestHTTPEndpointFinalization(t *testing.T) {
 	cases := map[string]struct {
 		DSL          func()
diff --git a/expr/testdata/endpoint_dsls.go b/expr/testdata/endpoint_dsls.go
index d304d6dc..df34fea9 100644
--- a/expr/testdata/endpoint_dsls.go
+++ b/expr/testdata/endpoint_dsls.go
@@ -252,15 +252,35 @@ var EndpointExtendToken = func() {
 }
 
 var EndpointHasParent = func() {
+	Service("Ancestor", func() {
+		HTTP(func() {
+			Path("/ancestor")
+			CanonicalMethod("Method")
+		})
+		Method("Method", func() {
+			Payload(func() {
+				Attribute("ancestor_id", Int)
+				Attribute("query_0", String)
+				Required("ancestor_id")
+			})
+			HTTP(func() {
+				GET("/{ancestor_id}")
+				Param("query_0")
+			})
+		})
+
+	})
 	Service("Parent", func() {
 		HTTP(func() {
 			Path("/parents")
 			CanonicalMethod("Method")
+			Parent("Ancestor")
 		})
 		Method("Method", func() {
 			Payload(func() {
 				Attribute("parent_id", Int)
 				Attribute("query_1", String)
+				Required("parent_id")
 			})
 			HTTP(func() {
 				GET("/{parent_id}")