NSwag
NSwag copied to clipboard
Typescript client generation with anyOf, oneOf, allOf
We're currently building out an OpenAPI specification for a legacy system (so handcrafted, no automated API generation), for use from an Angular application. We've used the allOf
and oneOf
constructs a few times, but have just found that the NSwag generation isn't quite supportive of these.
As a basic example (using constructs from the OpenAPI documentation):
paths:
/pets:
patch:
requestBody:
content:
application/json:
schema:
oneOf:
- $ref: '#/components/schemas/Cat'
- $ref: '#/components/schemas/Dog'
discriminator:
propertyName: pet_type
responses:
'200':
description: Updated
components:
schemas:
Pet:
type: object
required:
- pet_type
properties:
pet_type:
type: string
discriminator:
propertyName: pet_type
Dog: # "Dog" is a value for the pet_type property (the discriminator value)
allOf: # Combines the main `Pet` schema with `Dog`-specific properties
- $ref: '#/components/schemas/Pet'
- type: object
# all other properties specific to a `Dog`
properties:
bark:
type: boolean
breed:
type: string
enum: [Dingo, Husky, Retriever, Shepherd]
Cat: # "Cat" is a value for the pet_type property (the discriminator value)
allOf: # Combines the main `Pet` schema with `Cat`-specific properties
- $ref: '#/components/schemas/Pet'
- type: object
# all other properties specific to a `Cat`
properties:
hunts:
type: boolean
age:
type: integer
Is giving us:
/**
* @param body (optional)
* @return Updated
*/
pets(body: Cat | undefined): Promise<void> {
let url_ = this.baseUrl + "/pets";
url_ = url_.replace(/[?&]$/, "");
const content_ = JSON.stringify(body);
let options_ = <RequestInit>{
body: content_,
method: "PATCH",
headers: {
"Content-Type": "application/json",
}
};
return this.http.fetch(url_, options_).then((_response: Response) => {
return this.processPets(_response);
});
}
Notice that the pets()
method is only accepting a strongly typed Cat
instance, or an undefined
. No Dog
. If I generate classes instead of interfaces, I can see the generation using the pet_type
field to construct the correct instance from the Pet
class:
static fromJS(data: any, _mappings?: any): Pet | null {
data = typeof data === 'object' ? data : {};
if (data["pet_type"] === "Cat")
return createInstance<Cat>(data, _mappings, Cat);
if (data["pet_type"] === "Dog")
return createInstance<Dog>(data, _mappings, Dog);
return createInstance<Pet>(data, _mappings, Pet);
}
But the pets()
method is still the same. It's only accepting one of the strongly typed classes.
Is this expected? Is there any method of getting allOf
, oneOf
to generate correctly with using a TypeScript client.
I've seen past issues with comments that it should be working, as TypeScript is more flexible than C#, but it doesn't appear to be working for us.
Using v13.10.8.0.
Yes, that's a known issue, though I wasn't able to find an issue to duplicate this with. I think that the real issue is in NJsonSchema's typescript generatore instead of here, but there might be some impact here as well.
Ref: https://github.com/RicoSuter/NJsonSchema/issues/13
Something new about this Issue? Some workarounds?
I just ran into this as well, with a more complex setup
Is there any progress on this issue?