diff --git a/pkg/codegen/codegen_test.go b/pkg/codegen/codegen_test.go index 6ae61211a9..499174be03 100644 --- a/pkg/codegen/codegen_test.go +++ b/pkg/codegen/codegen_test.go @@ -201,6 +201,49 @@ type GetTestByNameResponse struct { checkLint(t, "test.gen.go", []byte(code)) } +// Validate any types nested under AdditionalPropertiesTypes is propagated up as with normal Property AdditionalTypes +func TestExampleOpenAPICodeGenerationSchemaAdditionalPropertyTypes(t *testing.T) { + + // Input vars for code generation: + packageName := "testswagger" + opts := Configuration{ + PackageName: packageName, + Generate: GenerateOptions{ + EchoServer: false, + Client: false, + Models: true, + EmbeddedSpec: false, + }, + } + + loader := openapi3.NewLoader() + loader.IsExternalRefsAllowed = true + + // Get a spec from the test definition in this file: + swagger, err := loader.LoadFromData([]byte(testSchemaArrayTypes)) + assert.NoError(t, err) + + // Run our code generation: + code, err := Generate(swagger, opts) + assert.NoError(t, err) + assert.NotEmpty(t, code) + + // Check that we have valid (formattable) code: + _, err = format.Source([]byte(code)) + assert.NoError(t, err) + + // Check that we have a package: + assert.Contains(t, code, "package testswagger") + + // Check that AdditionalPropertyTypes structs are propagated up properly: + assert.Contains(t, code, "[]PatchedBulkWritableCircuitTerminationRequest_Relationships_Destination_Objects_Item") + assert.Contains(t, code, "type PatchedBulkWritableCircuitTerminationRequest_Relationships_Destination_Objects_Item struct {") + assert.Contains(t, code, "[]BulkWritableCircuitTerminationRequest_Relationships_Destination_Objects_Item") + assert.Contains(t, code, "type BulkWritableCircuitTerminationRequest_Relationships_Destination_Objects_Item struct {") + assert.Contains(t, code, "[]WritableCircuitTerminationRequest_Relationships_Destination_Objects_Item ") + assert.Contains(t, code, "type WritableCircuitTerminationRequest_Relationships_Destination_Objects_Item struct {") +} + func TestGoTypeImport(t *testing.T) { packageName := "api" opts := Configuration{ @@ -309,5 +352,8 @@ func (t *ExampleSchema_Item) FromExternalRef0NewPet(v externalRef0.NewPet) error } +//go:embed test_schema_additional_properties_types.yaml +var testSchemaArrayTypes string + //go:embed test_spec.yaml var testOpenAPIDefinition string diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go index 457e102fe7..b29a86f04c 100644 --- a/pkg/codegen/schema.go +++ b/pkg/codegen/schema.go @@ -71,6 +71,11 @@ func (s Schema) GetAdditionalTypeDefs() []TypeDefinition { for _, p := range s.Properties { result = append(result, p.Schema.GetAdditionalTypeDefs()...) } + // Some schema definitions may be used for key/value and not specify any properties, but provide properties + // within the additionalProperties. See test_schema_array_types.yaml in tests. + if s.AdditionalPropertiesType != nil { + result = append(result, s.AdditionalPropertiesType.GetAdditionalTypeDefs()...) + } result = append(result, s.AdditionalTypes...) return result } diff --git a/pkg/codegen/test_schema_additional_properties_types.yaml b/pkg/codegen/test_schema_additional_properties_types.yaml new file mode 100644 index 0000000000..0cbf800d05 --- /dev/null +++ b/pkg/codegen/test_schema_additional_properties_types.yaml @@ -0,0 +1,513 @@ +openapi: 3.0.3 +info: + title: API Documentation + version: 1.5.7 (1.3) + description: Source of truth and network automation platform + license: + name: Apache v2 License +paths: + /circuits/circuit-terminations/: + post: + operationId: circuits_circuit_terminations_create + description: |- + Base class to use for API ViewSets based on OrganizationalModel or PrimaryModel. + + Can also be used for models derived from BaseModel, so long as they support Notes. + tags: + - circuits + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/WritableCircuitTerminationRequest" + required: true + security: + - cookieAuth: [] + - tokenAuth: [] + responses: + "201": + content: + application/json; version=1.3: + schema: + $ref: "#/components/schemas/CircuitTermination" + description: "" + put: + operationId: circuits_circuit_terminations_bulk_update + description: |- + Base class to use for API ViewSets based on OrganizationalModel or PrimaryModel. + + Can also be used for models derived from BaseModel, so long as they support Notes. + tags: + - circuits + requestBody: + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/BulkWritableCircuitTerminationRequest" + required: true + security: + - cookieAuth: [] + - tokenAuth: [] + responses: + "200": + content: + application/json; version=1.3: + schema: + type: array + items: + $ref: "#/components/schemas/CircuitTermination" + description: "" + patch: + operationId: circuits_circuit_terminations_bulk_partial_update + description: |- + Base class to use for API ViewSets based on OrganizationalModel or PrimaryModel. + + Can also be used for models derived from BaseModel, so long as they support Notes. + tags: + - circuits + requestBody: + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/PatchedBulkWritableCircuitTerminationRequest" + required: true + security: + - cookieAuth: [] + - tokenAuth: [] + responses: + "200": + content: + application/json; version=1.3: + schema: + type: array + items: + $ref: "#/components/schemas/CircuitTermination" + description: "" +components: + schemas: + CircuitTermination: + type: object + description: |- + Base class to use for serializers based on OrganizationalModel or PrimaryModel. + + Can also be used for models derived from BaseModel, so long as they support custom fields and relationships. + properties: + id: + type: string + format: uuid + readOnly: true + display: + type: string + readOnly: true + description: Human friendly display value + url: + type: string + format: uri + readOnly: true + description: + type: string + maxLength: 200 + required: + - display + - id + - url + WritableCircuitTerminationRequest: + type: object + description: |- + Base class to use for serializers based on OrganizationalModel or PrimaryModel. + + Can also be used for models derived from BaseModel, so long as they support custom fields and relationships. + properties: + circuit: + type: string + format: uuid + site: + type: string + format: uuid + nullable: true + location: + type: string + format: uuid + nullable: true + provider_network: + type: string + format: uuid + nullable: true + description: + type: string + maxLength: 200 + custom_fields: + type: object + additionalProperties: {} + relationships: + type: object + additionalProperties: + type: object + required: + - id + - url + - name + - type + properties: + id: + type: string + format: uuid + readOnly: true + url: + type: string + format: uri + readOnly: true + name: + type: string + readOnly: true + type: + type: string + readOnly: true + example: one-to-many + source: + type: object + properties: + label: + type: string + readOnly: true + object_type: + type: string + readOnly: true + example: dcim.site + objects: + type: array + items: + type: object + properties: + id: + type: string + format: uuid + url: + type: string + format: uri + readOnly: true + display: + type: string + readOnly: true + additionalProperties: true + destination: + type: object + properties: + label: + type: string + readOnly: true + object_type: + type: string + readOnly: true + example: dcim.site + objects: + type: array + items: + type: object + properties: + id: + type: string + format: uuid + url: + type: string + format: uri + readOnly: true + display: + type: string + readOnly: true + additionalProperties: true + peer: + type: object + properties: + label: + type: string + readOnly: true + object_type: + type: string + readOnly: true + example: dcim.site + objects: + type: array + items: + type: object + properties: + id: + type: string + format: uuid + url: + type: string + format: uri + readOnly: true + display: + type: string + readOnly: true + additionalProperties: true + required: + - circuit + BulkWritableCircuitTerminationRequest: + type: object + description: |- + Base class to use for serializers based on OrganizationalModel or PrimaryModel. + + Can also be used for models derived from BaseModel, so long as they support custom fields and relationships. + properties: + id: + type: string + format: uuid + description: + type: string + maxLength: 200 + custom_fields: + type: object + additionalProperties: true + relationships: + type: object + additionalProperties: + type: object + required: + - id + - url + - name + - type + properties: + id: + type: string + format: uuid + readOnly: true + url: + type: string + format: uri + readOnly: true + name: + type: string + readOnly: true + type: + type: string + readOnly: true + example: one-to-many + source: + type: object + properties: + label: + type: string + readOnly: true + object_type: + type: string + readOnly: true + example: dcim.site + objects: + type: array + items: + type: object + properties: + id: + type: string + format: uuid + url: + type: string + format: uri + readOnly: true + display: + type: string + readOnly: true + additionalProperties: true + destination: + type: object + properties: + label: + type: string + readOnly: true + object_type: + type: string + readOnly: true + example: dcim.site + objects: + type: array + items: + type: object + properties: + id: + type: string + format: uuid + url: + type: string + format: uri + readOnly: true + display: + type: string + readOnly: true + additionalProperties: true + peer: + type: object + properties: + label: + type: string + readOnly: true + object_type: + type: string + readOnly: true + example: dcim.site + objects: + type: array + items: + type: object + properties: + id: + type: string + format: uuid + url: + type: string + format: uri + readOnly: true + display: + type: string + readOnly: true + additionalProperties: true + required: + - id + PatchedBulkWritableCircuitTerminationRequest: + type: object + description: |- + Base class to use for serializers based on OrganizationalModel or PrimaryModel. + + Can also be used for models derived from BaseModel, so long as they support custom fields and relationships. + properties: + id: + type: string + format: uuid + port_speed: + type: integer + maximum: 2147483647 + minimum: 0 + nullable: true + title: Port speed (Kbps) + upstream_speed: + type: integer + maximum: 2147483647 + minimum: 0 + nullable: true + title: Upstream speed (Kbps) + description: Upstream speed, if different from port speed + xconnect_id: + type: string + title: Cross-connect ID + maxLength: 50 + pp_info: + type: string + title: Patch panel/port(s) + maxLength: 100 + description: + type: string + maxLength: 200 + custom_fields: + type: object + additionalProperties: {} + relationships: + type: object + additionalProperties: + type: object + required: + - id + - url + - name + - type + properties: + id: + type: string + format: uuid + readOnly: true + url: + type: string + format: uri + readOnly: true + name: + type: string + readOnly: true + type: + type: string + readOnly: true + example: one-to-many + source: + type: object + properties: + label: + type: string + readOnly: true + object_type: + type: string + readOnly: true + example: dcim.site + objects: + type: array + items: + type: object + properties: + id: + type: string + format: uuid + url: + type: string + format: uri + readOnly: true + display: + type: string + readOnly: true + additionalProperties: true + destination: + type: object + properties: + label: + type: string + readOnly: true + object_type: + type: string + readOnly: true + example: dcim.site + objects: + type: array + items: + type: object + properties: + id: + type: string + format: uuid + url: + type: string + format: uri + readOnly: true + display: + type: string + readOnly: true + additionalProperties: true + peer: + type: object + properties: + label: + type: string + readOnly: true + object_type: + type: string + readOnly: true + example: dcim.site + objects: + type: array + items: + type: object + properties: + id: + type: string + format: uuid + url: + type: string + format: uri + readOnly: true + display: + type: string + readOnly: true + additionalProperties: true + required: + - id