Repository: goadesign/goa
Pull request #3405 (2023-10-30 11:30:47)

Add openapi:generate Meta support to dsl.Server
## Usage

```go
Server("test", func() {
	Host("localhost", func() {
		URI("https://goa.design")
	})
	Meta("openapi:generate", "false")
})
```

## The suppressed documents

### openapi.json

```json
"host": "goa.design",
```

### openapi.yaml

```yaml
host: goa.design
```

### openapi3.json

```json
"servers": [
    {
        "url": "https://goa.design"
    }
],
```

### openapi3.yaml

```yaml
servers:
    - url: https://goa.design
```


raphael: This is great, thank you!

Patch:
diff --git a/dsl/meta.go b/dsl/meta.go
index 42c3b381..9a3a53df 100644
--- a/dsl/meta.go
+++ b/dsl/meta.go
@@ -130,7 +130,7 @@ import (
 // - "swagger:generate" DEPRECATED, use "openapi:generate" instead.
 //
 // - "openapi:generate" specifies whether OpenAPI specification should be
-// generated. Defaults to true. Applicable to services, methods and file
+// generated. Defaults to true. Applicable to Server, services, methods and file
 // servers.
 //
 //	var _ = Service("MyService", func() {
@@ -234,6 +234,8 @@ func Meta(name string, value ...string) {
 	switch e := eval.Current().(type) {
 	case *expr.APIExpr:
 		e.Meta = appendMeta(e.Meta, name, value...)
+	case *expr.ServerExpr:
+		e.Meta = appendMeta(e.Meta, name, value...)
 	case *expr.AttributeExpr:
 		e.Meta = appendMeta(e.Meta, name, value...)
 	case *expr.ResultTypeExpr:
diff --git a/expr/server.go b/expr/server.go
index cf5f742a..ad32c527 100644
--- a/expr/server.go
+++ b/expr/server.go
@@ -25,6 +25,8 @@ type (
 		Services []string
 		// Hosts list the server hosts.
 		Hosts []*HostExpr
+		// Meta is a set of key/value pairs.
+		Meta MetaExpr
 	}
 
 	// HostExpr describes a server host.
diff --git a/http/codegen/openapi/v2/builder.go b/http/codegen/openapi/v2/builder.go
index 359e2a8a..459d0357 100644
--- a/http/codegen/openapi/v2/builder.go
+++ b/http/codegen/openapi/v2/builder.go
@@ -25,6 +25,9 @@ func NewV2(root *expr.RootExpr, h *expr.HostExpr) (*V2, error) {
 		return nil, fmt.Errorf("failed to parse server URL: %s", err)
 	}
 	host := u.Host
+	if !mustGenerate(root.API.Servers[0].Meta) {
+		host = ""
+	}
 
 	basePath := root.API.HTTP.Path
 	if hasAbsoluteRoutes(root) {
diff --git a/http/codegen/openapi/v3/builder.go b/http/codegen/openapi/v3/builder.go
index 55034927..958003c5 100644
--- a/http/codegen/openapi/v3/builder.go
+++ b/http/codegen/openapi/v3/builder.go
@@ -485,6 +485,9 @@ func parseOperationIDTemplate(template, service, method string, routeIndex int)
 func buildServers(servers []*expr.ServerExpr) []*Server {
 	var svrs []*Server
 	for _, svr := range servers {
+		if !mustGenerate(svr.Meta) {
+			continue
+		}
 		var server *Server
 		for _, host := range svr.Hosts {
 			var (


Test patch:
diff --git a/http/codegen/openapi/v2/files_test.go b/http/codegen/openapi/v2/files_test.go
index c591a8f1..005cdf13 100644
--- a/http/codegen/openapi/v2/files_test.go
+++ b/http/codegen/openapi/v2/files_test.go
@@ -40,6 +40,7 @@ func TestSections(t *testing.T) {
 		{"with-spaces", testdata.WithSpacesDSL},
 		{"with-map", testdata.WithMapDSL},
 		{"path-with-wildcards", testdata.PathWithWildcardDSL},
+		{"not-generate-server", testdata.NotGenerateServerDSL},
 	}
 	for _, c := range cases {
 		t.Run(c.Name, func(t *testing.T) {
diff --git a/http/codegen/openapi/v2/testdata/TestSections/not-generate-server_file0.golden b/http/codegen/openapi/v2/testdata/TestSections/not-generate-server_file0.golden
new file mode 100644
index 00000000..49331c7d
--- /dev/null
+++ b/http/codegen/openapi/v2/testdata/TestSections/not-generate-server_file0.golden
@@ -0,0 +1,1 @@
+{"swagger":"2.0","info":{"title":"","version":""},"consumes":["application/json","application/xml","application/gob"],"produces":["application/json","application/xml","application/gob"],"paths":{"/":{"get":{"tags":["testService"],"summary":"testEndpoint testService","operationId":"testService#testEndpoint","responses":{"200":{"description":"OK response.","schema":{"type":"string"}}},"schemes":["https"]}}}}
\ No newline at end of file
diff --git a/http/codegen/openapi/v2/testdata/TestSections/not-generate-server_file1.golden b/http/codegen/openapi/v2/testdata/TestSections/not-generate-server_file1.golden
new file mode 100644
index 00000000..91737a72
--- /dev/null
+++ b/http/codegen/openapi/v2/testdata/TestSections/not-generate-server_file1.golden
@@ -0,0 +1,26 @@
+swagger: "2.0"
+info:
+    title: ""
+    version: ""
+consumes:
+    - application/json
+    - application/xml
+    - application/gob
+produces:
+    - application/json
+    - application/xml
+    - application/gob
+paths:
+    /:
+        get:
+            tags:
+                - testService
+            summary: testEndpoint testService
+            operationId: testService#testEndpoint
+            responses:
+                "200":
+                    description: OK response.
+                    schema:
+                        type: string
+            schemes:
+                - https
diff --git a/http/codegen/openapi/v3/files_test.go b/http/codegen/openapi/v3/files_test.go
index 82fdfc62..31f8a9db 100644
--- a/http/codegen/openapi/v3/files_test.go
+++ b/http/codegen/openapi/v3/files_test.go
@@ -45,6 +45,7 @@ func TestFiles(t *testing.T) {
 		{"with-tags", testdata.WithTagsDSL},
 		{"with-tags-swagger", testdata.WithTagsSwaggerDSL},
 		{"typename", testdata.TypenameDSL},
+		{"not-generate-server", testdata.NotGenerateServerDSL},
 		// TestEndpoints
 		{"endpoint", testdata.ExtensionDSL},
 		{"endpoint-swagger", testdata.ExtensionSwaggerDSL},
diff --git a/http/codegen/openapi/v3/testdata/golden/not-generate-server_file0.golden b/http/codegen/openapi/v3/testdata/golden/not-generate-server_file0.golden
new file mode 100644
index 00000000..d6c2a6b5
--- /dev/null
+++ b/http/codegen/openapi/v3/testdata/golden/not-generate-server_file0.golden
@@ -0,0 +1,1 @@
+{"openapi":"3.0.3","info":{"title":"Goa API","version":"1.0"},"paths":{"/":{"get":{"tags":["testService"],"summary":"testEndpoint testService","operationId":"testService#testEndpoint","responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"type":"string","example":"Beatae non id consequatur."},"example":"Aut sed ducimus repudiandae sit explicabo asperiores."}}}}}}},"components":{},"tags":[{"name":"testService"}]}
\ No newline at end of file
diff --git a/http/codegen/openapi/v3/testdata/golden/not-generate-server_file1.golden b/http/codegen/openapi/v3/testdata/golden/not-generate-server_file1.golden
new file mode 100644
index 00000000..8bc6e693
--- /dev/null
+++ b/http/codegen/openapi/v3/testdata/golden/not-generate-server_file1.golden
@@ -0,0 +1,23 @@
+openapi: 3.0.3
+info:
+    title: Goa API
+    version: "1.0"
+paths:
+    /:
+        get:
+            tags:
+                - testService
+            summary: testEndpoint testService
+            operationId: testService#testEndpoint
+            responses:
+                "200":
+                    description: OK response.
+                    content:
+                        application/json:
+                            schema:
+                                type: string
+                                example: Beatae non id consequatur.
+                            example: Aut sed ducimus repudiandae sit explicabo asperiores.
+components: {}
+tags:
+    - name: testService
diff --git a/http/codegen/testdata/openapi_dsls.go b/http/codegen/testdata/openapi_dsls.go
index 29ded6c7..dae8f1f4 100644
--- a/http/codegen/testdata/openapi_dsls.go
+++ b/http/codegen/testdata/openapi_dsls.go
@@ -718,3 +718,22 @@ var SkipResponseBodyEncodeDecodeDSL = func() {
 		})
 	})
 }
+
+var NotGenerateServerDSL = func() {
+	var _ = API("test", func() {
+		Server("test", func() {
+			Host("localhost", func() {
+				URI("https://goa.design")
+			})
+			Meta("openapi:generate", "false")
+		})
+	})
+	Service("testService", func() {
+		Method("testEndpoint", func() {
+			Result(String)
+			HTTP(func() {
+				GET("/")
+			})
+		})
+	})
+}