Skip to content

fix: #1530 support discriminator with multiple mappings of same schema#1789

Closed
mgabeler-lee-6rs wants to merge 14 commits into
oapi-codegen:mainfrom
mgabeler-lee-6rs:fix-1530-mgl
Closed

fix: #1530 support discriminator with multiple mappings of same schema#1789
mgabeler-lee-6rs wants to merge 14 commits into
oapi-codegen:mainfrom
mgabeler-lee-6rs:fix-1530-mgl

Conversation

@mgabeler-lee-6rs

@mgabeler-lee-6rs mgabeler-lee-6rs commented Oct 2, 2024

Copy link
Copy Markdown
Contributor

This is an improved version of @jKiler's #1534. Credit to them for getting this started.

My main addition is getting the codegen for FromFoo and MergeFoo to work better in this situation.

@mweibel

mweibel commented Oct 4, 2024

Copy link
Copy Markdown

thanks a lot! that PR supersedes #1745 and works better 👍 and fixes #1668 too

@tkuik

tkuik commented Oct 28, 2024

Copy link
Copy Markdown

Maintainers / @mgabeler-lee-6rs what is the plan for this PR?

@mgabeler-lee-6rs

Copy link
Copy Markdown
Contributor Author

I've been using this PR in my production app for some time now with good results. It's not perfect, it's vulnerable to GIGO if you have an invalid OAS spec, but no worse than the released code.

Contribution guidelines explicitly request not tagging maintainers directly 🤷‍♂️

@gerhardwagner

Copy link
Copy Markdown

would like to see this merged

@benazir-sba

Copy link
Copy Markdown

this PR would solve my problems 😸

@lukasbash

Copy link
Copy Markdown

Would need this merged too! Does this PR fix the issue that untyped string constants are used within the generated files?

image

@mgabeler-lee-6rs

Copy link
Copy Markdown
Contributor Author

Does this PR fix the issue that untyped string constants are used within the generated files?

I haven't seen that issue personally, so I can't say for sure. Probably the easiest way to find out is to just try it 🙂

@champtar

Copy link
Copy Markdown

I have the same issue as @lukasbash and this PR doesn't fix the issue for me

@mgabeler-lee-6rs

Copy link
Copy Markdown
Contributor Author

@champtar or @lukasbash can you share a repro for the issue you're seeing?

@champtar

Copy link
Copy Markdown

@mgabeler-lee-6rs here a minimal reproducer that break with v2.4.1

openapi: 3.0.4
info:
  title: test
  version: v1
paths:
  /aaa:
    get:
      operationId: aaa
      responses:
        '200':
          description: successful operation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/objX'
components:
  schemas:
    objstr:
      type: string
    objint:
      type: integer
    objX:
      anyOf:
        - $ref: '#/components/schemas/objstr'
        - $ref: '#/components/schemas/objint'
      discriminator:
        propertyName: mytype
        mapping:
          "int": '#/components/schemas/objint'
          "str": '#/components/schemas/objstr'

@mgabeler-lee-6rs

mgabeler-lee-6rs commented Mar 27, 2025

Copy link
Copy Markdown
Contributor Author

@champtar I tried adding that as a test case on this branch and it produces compiling code not showing the pattern lukasbash reported. This seems to be in part because your example didn't include a definition for the mytype property, so it has no reference to that in the generated code (the type of "invalid specs produce GIGO" I referenced earlier). However even if I add the property as an enum, so that there's a generated type for it and not just an alias to string, the code still compiles just fine because ...

Assigning an untyped string constant to a type that is defined as a string ... is not an error.

Do you have some more complex setup outside your minimal repro where the discriminator field type is generated as something other than type Foo string such that assigning a string to it is actually an error?


Edited to add: Your example is additionally invalid because you are defining a discriminator property on an (implicitly) object schema, but the two discriminator possibilities both then say that it is not an object, so your schema is unsatisfiable.

@mgabeler-lee-6rs

Copy link
Copy Markdown
Contributor Author

I've pushed up an adapted version of your example case, with the valid code it creates. If you can find further adjustments that show it producing invalid code, I'm happy to improve the PR :)

@champtar

Copy link
Copy Markdown

@mgabeler-lee-6rs my example might be invalid, but it pass online validators like https://editor.swagger.io/ :(

I was trying to construct a minimal example and not share 5k lines of spec, here a better one actually closer to the spec I'm trying to deal with

openapi: 3.0.4
info:
  title: test
  version: v1
paths:
  /aaa:
    get:
      operationId: aaa
      responses:
        "200":
          description: successful operation
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/objX"
components:
  schemas:
    objstr:
      type: object
      #required: [objectType]
      properties:
        objectType:
          type: string
          enum: ["str"]
    objint:
      type: object
      #required: [objectType]
      properties:
        objectType:
          type: string
          enum: ["int"]
    objX:
      anyOf:
        - $ref: "#/components/schemas/objstr"
        - $ref: "#/components/schemas/objint"
      discriminator:
        propertyName: objectType
        mapping:
          "int": "#/components/schemas/objint"
          "str": "#/components/schemas/objstr"

Basically the spec I'm dealing with is missing the required: [objectType]

https://spec.openapis.org/oas/v3.1.0.html#fixed-fields-20

The expectation now is that a property with name petType MUST be present in the response payload, and the value will correspond to the name of a schema defined in the OAS document.

@mgabeler-lee-6rs

Copy link
Copy Markdown
Contributor Author

Aah, a schema with the discriminator field optional. So the issue isn't about using an untyped string constant, but rather using a string instead of a pointer to a string ✔️

I'll see if I can update this PR to handle that better. However it might be necessary to simply add x-go-type-skip-optional-pointer onto the discriminator fields

@champtar

Copy link
Copy Markdown

How I read the spec (https://spec.openapis.org/oas/v3.1.0.html#fixed-fields-20) the field MUST be present, is there a notion of implicit required in OpenAPI ? Else it's just a buggy schema.

@mgabeler-lee-6rs

mgabeler-lee-6rs commented Mar 27, 2025

Copy link
Copy Markdown
Contributor Author

It certainly reads kinda like it's an implicit required, but I'm not completely clear on that.

I've got something half-way working to process this, but the challenge I'm running into is that the point at which we are rendering the code that needs to know the type of e.g. Objstr.ObjectType, the codegen system doesn't have a reference to the real codegen info for the Objstr type, it only knows its name (because it was given via a $ref), so the codegen can't know if the discriminator field in it is normal, a pointer, or a nullable.

I've pushed up what I can do to make this better without invasive surgery, and the test example now shows the two options for how to get your example schema to generate valid code.

@champtar

Copy link
Copy Markdown

@mgabeler-lee-6rs FYI in 3.1.1 it's clearer https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.1.md#fixed-fields-22

This property SHOULD be required in the payload schema, as the behavior when the property is absent is undefined.

@jeremyfiel

Copy link
Copy Markdown

even more clear definition of said behavior will be available in the upcoming OAS 3.2 minor release slated for Summer '25. That doesn't fix the older versions, but it definitely provides direction for implementations which is backwards compatible with earlier versions.

Redocly/redocly-cli#2028 (comment)

@kusari-inspector

Copy link
Copy Markdown

Kusari Analysis Results

Analysis for commit: 2fef48e, performed at: 2025-07-16T14:00:57Z

@kusari-inspector rerun - Trigger a re-analysis of this PR

@kusari-inspector feedback [your message] - Send feedback to our AI and team


Recommendation

✅ PROCEED with this Pull Request

Summary

No Flagged Issues Detected

All values appear to be within acceptable risk parameters.

No pinned version dependency changes, code issues or exposed secrets detected!

Found this helpful? Give it a 👍 or 👎 reaction!

@mromaszewicz

Copy link
Copy Markdown
Member

Thank you for submitting this PR, @mgabeler-lee-6rs — but we need to close it because the core fix landed independently via #2071 (commit b658fcff), which removed the early break so all mappings per schema are recorded, updated the validation check (from \!= len(elements) to < len(elements)), and added a $numberOfUnionTypes guard in union.tmpl for From/Merge methods. A repro against current main generates correct ValueByDiscriminator() with all switch cases.

Thanks for the contribution and for diagnosing the root cause.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants