Repository: goadesign/goa
Pull request #3451 (2024-01-17 04:00:44)

Standardize OpenAPI integer format
Use the `int64` format for:
* `Int64` and `UInt64`:  The OpenAPI specification does not have a dedicated format for unsigned integers.
* `Int` and `UInt`: This is so that the default OpenAPI generator produces `int64` instead of `int32` for standard integers.

Use the `int32` format for:
* `Int32` and `UInt32`



Patch:
diff --git a/http/codegen/openapi/json_schema.go b/http/codegen/openapi/json_schema.go
index 668904ba..e1ba5fae 100644
--- a/http/codegen/openapi/json_schema.go
+++ b/http/codegen/openapi/json_schema.go
@@ -164,7 +164,7 @@ func APISchema(api *expr.APIExpr, r *expr.RootExpr) *Schema {
 }
 
 // GenerateServiceDefinition produces the JSON schema corresponding to the given
-// service. It stores the results in cachedSchema.
+// service. It stores the results in Definitions.
 func GenerateServiceDefinition(api *expr.APIExpr, res *expr.HTTPServiceExpr) {
 	s := NewSchema()
 	s.Description = res.Description()
@@ -322,6 +322,8 @@ func TypeSchemaWithPrefix(api *expr.APIExpr, t expr.DataType, prefix string) *Sc
 			s.Format = "binary"
 		case expr.IntKind, expr.Int64Kind,
 			expr.UIntKind, expr.UInt64Kind:
+			// Use int64 format for IntKind and UIntKind because the OpenAPI
+			// generator produced int32 by default.
 			s.Type = Type("integer")
 			s.Format = "int64"
 		case expr.Int32Kind, expr.UInt32Kind:
diff --git a/http/codegen/openapi/v3/types.go b/http/codegen/openapi/v3/types.go
index 42b1f181..ee675afe 100644
--- a/http/codegen/openapi/v3/types.go
+++ b/http/codegen/openapi/v3/types.go
@@ -152,12 +152,12 @@ func (sf *schemafier) schemafy(attr *expr.AttributeExpr, noref ...bool) *openapi
 	switch t := attr.Type.(type) {
 	case expr.Primitive:
 		switch t.Kind() {
-		case expr.UIntKind, expr.UInt64Kind, expr.UInt32Kind:
-			s.Type = openapi.Type("integer")
-		case expr.IntKind, expr.Int64Kind:
+		case expr.IntKind, expr.UIntKind, expr.Int64Kind, expr.UInt64Kind:
+			// Use int64 format for IntKind and UIntKind because the OpenAPI
+			// generator produced int32 by default.
 			s.Type = openapi.Type("integer")
 			s.Format = "int64"
-		case expr.Int32Kind:
+		case expr.Int32Kind, expr.UInt32Kind:
 			s.Type = openapi.Type("integer")
 			s.Format = "int32"
 		case expr.Float32Kind:


Test patch:
diff --git a/http/codegen/openapi/v3/testdata/golden/with-map_file0.golden b/http/codegen/openapi/v3/testdata/golden/with-map_file0.golden
index 2eea907d..ab968e9b 100644
--- a/http/codegen/openapi/v3/testdata/golden/with-map_file0.golden
+++ b/http/codegen/openapi/v3/testdata/golden/with-map_file0.golden
@@ -1,1 +1,1 @@
-{"openapi":"3.0.3","info":{"title":"Goa API","version":"0.0.1"},"servers":[{"url":"http://localhost:80","description":"Default server for test api"}],"paths":{"/":{"post":{"tags":["test service"],"summary":"test endpoint test service","operationId":"test service#test endpoint","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestEndpointRequestBody"},"example":{"int_map":{"":1},"type_map":{"":{"string":""}},"uint_map":{"":1}}}}},"responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestEndpointResponseBody"},"example":{"resulttype_map":{"":{"bar":[{"string":""},{"string":""},{"string":""},{"string":""}],"foo":""}},"uint32_map":{"":1},"uint64_map":{"":1}}}}}}}}},"components":{"schemas":{"Bar":{"type":"object","properties":{"string":{"type":"string","example":""}},"example":{"string":""}},"GoaFoobar":{"type":"object","properties":{"bar":{"type":"array","items":{"$ref":"#/components/schemas/Bar"},"example":[{"string":""},{"string":""},{"string":""},{"string":""}]},"foo":{"type":"string","example":""}},"example":{"bar":[{"string":""},{"string":""},{"string":""},{"string":""}],"foo":""}},"TestEndpointRequestBody":{"type":"object","properties":{"int_map":{"type":"object","example":{"":1},"additionalProperties":{"type":"integer","example":1,"format":"int64"}},"type_map":{"type":"object","example":{"":{"string":""}},"additionalProperties":{"$ref":"#/components/schemas/Bar"}},"uint_map":{"type":"object","example":{"":1},"additionalProperties":{"type":"integer","example":1}}},"example":{"int_map":{"":1},"type_map":{"":{"string":""}},"uint_map":{"":1}}},"TestEndpointResponseBody":{"type":"object","properties":{"resulttype_map":{"type":"object","example":{"":{"bar":[{"string":""},{"string":""},{"string":""},{"string":""}],"foo":""}},"additionalProperties":{"$ref":"#/components/schemas/GoaFoobar"}},"uint32_map":{"type":"object","example":{"":1},"additionalProperties":{"type":"integer","example":1}},"uint64_map":{"type":"object","example":{"":1},"additionalProperties":{"type":"integer","example":1}}},"example":{"resulttype_map":{"":{"bar":[{"string":""},{"string":""},{"string":""},{"string":""}],"foo":""}},"uint32_map":{"":1},"uint64_map":{"":1}}}}},"tags":[{"name":"test service"}]}
\ No newline at end of file
+{"openapi":"3.0.3","info":{"title":"Goa API","version":"0.0.1"},"servers":[{"url":"http://localhost:80","description":"Default server for test api"}],"paths":{"/":{"post":{"tags":["test service"],"summary":"test endpoint test service","operationId":"test service#test endpoint","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestEndpointRequestBody"},"example":{"int_map":{"":1},"type_map":{"":{"string":""}},"uint_map":{"":1}}}}},"responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestEndpointResponseBody"},"example":{"resulttype_map":{"":{"bar":[{"string":""},{"string":""},{"string":""},{"string":""}],"foo":""}},"uint32_map":{"":1},"uint64_map":{"":1}}}}}}}}},"components":{"schemas":{"Bar":{"type":"object","properties":{"string":{"type":"string","example":""}},"example":{"string":""}},"GoaFoobar":{"type":"object","properties":{"bar":{"type":"array","items":{"$ref":"#/components/schemas/Bar"},"example":[{"string":""},{"string":""},{"string":""},{"string":""}]},"foo":{"type":"string","example":""}},"example":{"bar":[{"string":""},{"string":""},{"string":""},{"string":""}],"foo":""}},"TestEndpointRequestBody":{"type":"object","properties":{"int_map":{"type":"object","example":{"":1},"additionalProperties":{"type":"integer","example":1,"format":"int64"}},"type_map":{"type":"object","example":{"":{"string":""}},"additionalProperties":{"$ref":"#/components/schemas/Bar"}},"uint_map":{"type":"object","example":{"":1},"additionalProperties":{"type":"integer","example":1,"format":"int64"}}},"example":{"int_map":{"":1},"type_map":{"":{"string":""}},"uint_map":{"":1}}},"TestEndpointResponseBody":{"type":"object","properties":{"resulttype_map":{"type":"object","example":{"":{"bar":[{"string":""},{"string":""},{"string":""},{"string":""}],"foo":""}},"additionalProperties":{"$ref":"#/components/schemas/GoaFoobar"}},"uint32_map":{"type":"object","example":{"":1},"additionalProperties":{"type":"integer","example":1,"format":"int32"}},"uint64_map":{"type":"object","example":{"":1},"additionalProperties":{"type":"integer","example":1,"format":"int64"}}},"example":{"resulttype_map":{"":{"bar":[{"string":""},{"string":""},{"string":""},{"string":""}],"foo":""}},"uint32_map":{"":1},"uint64_map":{"":1}}}}},"tags":[{"name":"test service"}]}
\ No newline at end of file
diff --git a/http/codegen/openapi/v3/testdata/golden/with-map_file1.golden b/http/codegen/openapi/v3/testdata/golden/with-map_file1.golden
index 9fdc2a81..468936f4 100644
--- a/http/codegen/openapi/v3/testdata/golden/with-map_file1.golden
+++ b/http/codegen/openapi/v3/testdata/golden/with-map_file1.golden
@@ -103,6 +103,7 @@ components:
                     additionalProperties:
                         type: integer
                         example: 1
+                        format: int64
             example:
                 int_map:
                     "": 1
@@ -133,6 +134,7 @@ components:
                     additionalProperties:
                         type: integer
                         example: 1
+                        format: int32
                 uint64_map:
                     type: object
                     example:
@@ -140,6 +142,7 @@ components:
                     additionalProperties:
                         type: integer
                         example: 1
+                        format: int64
             example:
                 resulttype_map:
                     "":