-
-
Notifications
You must be signed in to change notification settings - Fork 6.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Typescript] Generate oneOf schemas as type unions #19027
[Typescript] Generate oneOf schemas as type unions #19027
Conversation
@@ -12,7 +12,7 @@ import { HttpFile } from '../http/http{{importFileExtension}}'; | |||
*/ | |||
{{/description}} | |||
{{^isEnum}} | |||
export class {{classname}} {{#parent}}extends {{{.}}} {{/parent}}{ | |||
{{#oneOf}}{{#-first}}{{>model/modelOneOf}}{{/-first}}{{/oneOf}}{{^oneOf}}export class {{classname}} {{#parent}}extends {{{.}}} {{/parent}}{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
{{#oneOf}}{{#-first}}{{>model/modelOneOf}}{{/-first}}{{/oneOf}}{{^oneOf}}export class {{classname}} {{#parent}}extends {{{.}}} {{/parent}}{ | |
{{#oneOf}} | |
{{#-first}}{{>model/modelOneOf}}{{/-first}} | |
{{/oneOf}} | |
{{^oneOf}} | |
export class {{classname}} {{#parent}}extends {{{.}}} {{/parent}}{ |
'bark'?: boolean; | ||
'breed'?: PetsPatchRequestBreedEnum; | ||
|
||
static readonly discriminator: string | undefined = "petType"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this changes the discriminator value to undefined, since we have
openapi-generator/samples/openapi3/client/petstore/typescript/builds/composed-schemas/models/Dog.ts
Line 19 in 8473d47
static readonly discriminator: string | undefined = undefined; |
is this intentional?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, intentional
I've created type and class:
/**
* @type PetsPatchRequest
* Type
* @export
*/
export type PetsPatchRequest = Cat | Dog;
/**
* @type PetsPatchRequestClass
* @export
*/
export class PetsPatchRequestClass {
static readonly discriminator: string | undefined = "petType";
static readonly mapping: {[index: string]: string} | undefined = undefined;
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this does not seem to be backwards compatible, is it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure, because now it isn't work at all
Should I make a PR to 8.0.x?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so you are saying the currently generated classes (before this PR) for the typescript generator dont work? what does not work?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just so i correctly understand, can you update the PR description with the motivation why this change is needed, what use case it solves, and why there are two types generated (the union and the class), and why the class does not have any fields besides a mapping and discriminator?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've updated the PR description.
Could you check it, please?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any updates?
@macjohnny
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any updates?
@macjohnny @wing328
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will check soon. Sorry, for the delay
@ksvirkou-hubspot given that this implementation is for oneOf, will this implementation throw an error if the JSON payload for example matches both models/schemes (e.g. Pet, Animal) defined in oneOf? |
Let me clarify the way ... should work. oneOf:
- $ref: '#/components/schemas/Cat'
- $ref: '#/components/schemas/Dog'
- $ref: '#/components/schemas/Lizard'
discriminator:
propertyName: petType Example of payload: {
"id": 123,
"petType": "Cat",
} In this case : Cat model. |
Could you check it, please? |
I ran into a similar issue in planet-a-ventures/affinity-node#35 and was passed on this PR by @macjohnny. I tried regenerating with the changes in this PR and it changes a broken implementation of https://github.com/planet-a-ventures/affinity-node/blob/32fd4f2deea3cb7723fca17353bb35d6b2d19bda/openapi/2024-08-28.json into a working one with correct discrimination of Here is the runtime output of the code generated from current
please note how the With the changes in this PR, this becomes:
which is correct (see how the entity is correctly of class I also noticed that this PR does make the changes in #19481 superfluous. E.g. if this PR is merged, #19481 (4238f17) can be reverted. |
I created #19494 that has the necessary revert, upstream changes from |
This pull request either needs all commits from #19494 or #19494 can be merged and it will automatically close this one as well, as it contains all the commits. I tried opening #19494 directly against your fork @ksvirkou-hubspot, however because of the commits that have made it to @macjohnny I can confirm that the generated code in this PR fixes the issue discussed before, both from a semantic perspective when looking at the code as well as in runtime (tried it against the live API, see above), so we should try to get this PR in as soon as possible, if we can, I think it will help anyone with swagger definitions that contain |
@ksvirkou-hubspot thanks for the fix! @joscha thanks for investigating and preparing the final PR. all merged. |
@macjohnny I just noticed that this change seems to generate nullable enums with an extra E.g: "enrichmentSource": {
"description": "The source of the data in this Field (if it is enriched)",
"enum": [
"affinity-data",
"dealroom",
null
],
"example": "affinity-data",
"type": "string",
"nullable": true
}, becomes export enum FieldEnrichmentSourceEnum {
AffinityData = 'affinity-data',
Dealroom = 'dealroom',
Null = 'null'
} which is incorrect as |
thanks for pointing this out and fixing! |
fix is in #19540 |
Description of the PR
I have implemented
oneOf
schemas as a type union and aoneOf
class with a discriminator and mapping, similar to PR 2617 and PR 2647, but for the TypeScript generator.The type union is used for methods like request/response types and for models as a type of parameters. The
oneOf
class is used for the deserialization process to determine the type of an object from the type union. It checks the discriminator in the mapping list, then in the list of all classes.Before this PR, the TypeScript generator created a new model with all fields from all
oneOf
models. The created model is not described in the swagger files. There are the following problems:oneOf
models have fields with the same name but different types.oneOf
models have enum fields with the same name but different values in the enum.oneOf
has a mapping list.oneOf
models contain required fields, a user has to set all required fields, even if they are not needed for the request.example:
Dog's required fields:
openapi-generator/samples/openapi3/client/petstore/typescript/builds/composed-schemas/models/Dog.ts
Lines 15 to 17 in daf5222
Cat's required fields:
openapi-generator/samples/openapi3/client/petstore/typescript/builds/composed-schemas/models/Cat.ts
Lines 15 to 17 in daf5222
oneOf
model required fields :openapi-generator/samples/openapi3/client/petstore/typescript/builds/composed-schemas/models/PetsPatchRequest.ts
Lines 17 to 21 in daf5222
if we sent Dog model we have to set all required fields to
PetsPatchRequest
(even cat's ones)oneOf
. If generate docs by the swagger with "oneOf", it won’t match the generated docs.The implementation "oneOf" schemas as a type union resolve all these problems, making the generated code accurate with the swagger specification.
Sample input:
Sample output:
PR checklist
master
(upcoming 7.6.0 minor release - breaking changes with fallbacks),8.0.x
(breaking changes without fallbacks)Related issues:
#9305