NSwag icon indicating copy to clipboard operation
NSwag copied to clipboard

Typescript client generation with anyOf, oneOf, allOf

Open danielbecroft opened this issue 3 years ago • 6 comments

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.

danielbecroft avatar Mar 31 '21 08:03 danielbecroft

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.

jeremyVignelles avatar Mar 31 '21 10:03 jeremyVignelles

Ref: https://github.com/RicoSuter/NJsonSchema/issues/13

RicoSuter avatar Apr 13 '21 08:04 RicoSuter

Something new about this Issue? Some workarounds?

nardo7 avatar Nov 29 '21 10:11 nardo7

I just ran into this as well, with a more complex setup

c3fr4 avatar Sep 07 '22 09:09 c3fr4

Is there any progress on this issue?

Dementiy avatar Jun 08 '23 13:06 Dementiy