typespec icon indicating copy to clipboard operation
typespec copied to clipboard

tsp-openapi3 - allOf with more than one member not supported

Open chrisradek opened this issue 1 year ago • 0 comments

Describe the bug

Currently tsp-openapi3 only includes allOf members in a generated TypeSpec model if there is one referenced member. In this case, the generated model extends the allOf member.

Instead the default behavior should be that all allOf members are spread into the generated TypeSpec model.

We may also need to support extending one of the allOf members if all of the following is true:

  • One and only one of the members has a discriminator
  • The discriminated member is a reference and not an in-line schema

Reproduction

openapi: 3.0.0
info:
  title: Sample
  version: 0.0.0
tags: []
paths: {}
components:
  schemas:
    Cat:
      allOf:
        - $ref: "#/components/schemas/Pet"
        - type: object
          required:
            - kind
            - name
          properties:
            kind:
              type: string
              enum:
                - cat
            name:
              type: string
    Pet:
      type: object
      required:
        - kind
      properties:
        kind:
          type: string
      discriminator:
        propertyName: kind
        mapping:
          cat: "#/components/schemas/Cat"

currently generates

import "@typespec/http";
import "@typespec/openapi";
import "@typespec/openapi3";

using Http;
using OpenAPI;

@service({
  title: "Sample",
})
@info({
  version: "0.0.0",
})
namespace Sample;

model Cat {}

@discriminator("kind")
model Pet {
  kind: string;
}

The Cat model is empty since more than 1 allOf is not supported. However, if the in-lined schema was moved from Cat's allOf to the schema's root:

openapi: 3.0.0
info:
  title: Sample
  version: 0.0.0
tags: []
paths: {}
components:
  schemas:
    Cat:
      type: object
      required:
        - kind
        - name
      properties:
        kind:
          type: string
          enum:
            - cat
        name:
          type: string
      allOf:
        - $ref: "#/components/schemas/Pet"
    Pet:
      type: object
      required:
        - kind
      properties:
        kind:
          type: string
      discriminator:
        propertyName: kind
        mapping:
          cat: "#/components/schemas/Cat"

then the correct output is generated:

import "@typespec/http";
import "@typespec/openapi";
import "@typespec/openapi3";

using Http;
using OpenAPI;

@service({
  title: "Sample",
})
@info({
  version: "0.0.0",
})
namespace Sample;

model Cat extends Pet {
  kind: "cat";
  name: string;
}

@discriminator("kind")
model Pet {
  kind: string;
}

Checklist

chrisradek avatar Aug 12 '24 22:08 chrisradek