apple / swift-openapi-generator

Generate Swift client and server code from an OpenAPI document.
https://swiftpackageindex.com/apple/swift-openapi-generator/documentation
Apache License 2.0
1.21k stars 87 forks source link

allOf plus properties #563

Closed niklassaers closed 1 month ago

niklassaers commented 1 month ago

Question

Hi, first of all thank you so much for making and maintaining this project :-)

I have an issue that when I have a component whos schema includes an allOf and properties, the properties don't appear in the code. As soon as I remove the allOf, the new properties are back. What can I do to get both the inherited and the new properties?

In my example, I have a super component BaseType that has a specialisation BaseWithModulesType. Then I have the type that I expect to return from my API which is RootType that is a BaseWithModulesType plus a few properties. RootType has a unique property moreModules but that one never appears in the generated Swift code

Here is the YAML in question:

openapi: 3.1.0
info:
    title: Content API
    description: >
        Example of unexpected behaviour
    version: 3.x.x

servers:
    - url: https://dev.my.tld
      description: Development

paths:
    /api/v1/example:
        get:
            tags:
                - Tag
            summary: My summary
            operationId: getExample
            parameters:
                - name: path
                  in: query
                  description: The slug to identify the content for a page
                  required: true
                  schema:
                      type: string
                  example: "/"
            responses:
                "200":
                    description: Success
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/RootType"

components:
    schemas:
        RootType:
            required:
                - type
            type: object
            allOf:
                - $ref: "#/components/schemas/BaseWithModulesType"
            properties:
                type:
                    pattern: RootType
                    type: string
                moreModules:
                    type: array
                    minItems: 0
                    items:
                        anyOf:
                            - $ref: "#/components/schemas/LeafAType"
                            - $ref: "#/components/schemas/LeafBType"
                            - $ref: "#/components/schemas/LeafCType"
        LeafAType:
            required:
                - type
                - image
            type: object
            properties:
                callToAction:
                    type:
                        - string
                headline:
                    type:
                        - string
                        - "null"
                subHeadline:
                    type:
                        - string
                        - "null"
                image:
                    type:
                        - string
                type:
                    pattern: LeafAType
                    type: string

        LeafBType:
            required:
                - categories
                - type
            type: object
            properties:
                type:
                    pattern: LeafBType
                    type: string
                headline:
                    type:
                        - string
                        - "null"
                categories:
                    type: array
                    minItems: 1
                    items:
                        type: string

        LeafCType:
            required:
                - productId
                - type
            type: object
            properties:
                productId:
                    type:
                        - string
                headline:
                    type:
                        - string
                        - "null"
                type:
                    pattern: LeafCType
                    type: string

        BaseType:
            required:
                - type
            type: object
            properties:
                type:
                    type: string
                breadcrumb:
                    type: string
            discriminator:
                propertyName: type

        BaseWithModulesType:
            required:
                - modules
            type: object
            allOf:
                - $ref: "#/components/schemas/BaseType"
            properties:
                modules:
                    type: array
                    minItems: 1
                    items:
                        anyOf:
                            - $ref: "#/components/schemas/LeafAType"
                            - $ref: "#/components/schemas/LeafBType"
                            - $ref: "#/components/schemas/LeafCType"
            discriminator:
                propertyName: type

So my test for this could be: Given that "swift-openapi-generator generate" is called with the OpenAPI document above, does "moreModules" appear in Types.swift?

Is there anything I can do already to make "moreModules" appear? :-) Perhaps there's some way I can format the OpenAPI? The source OpenAPI document uses allOf with BaseType and BaseWithModulesType a lot, so I don't think duplicating the properties around is an option.

czechboy0 commented 1 month ago

Hi @niklassaers,

I think the issue here is that you have schemas that try to be both an object and an allOf. But that won't work here.

Try to fix this by updating RootType to:

        RootType:
            allOf:
                - $ref: "#/components/schemas/BaseWithModulesType"
                - type: object
                  required:
                     - type
                  properties: ...

Basically, move the attributes of the object schema into a second subschema of the allOf.

And in BaseWithModulesType, you can remove discriminator - that's only used with oneOfs.

niklassaers commented 1 month ago

Hi @czechboy0, thank you very much for your quick response. Thank you also a ton for pointing out the mistake in how to use allOf with an object, none of the validators that I had used had picked up on that and I thought it was correct. I've corrected that now, and that works beautifully.