yonaskolb / SwagGen

OpenAPI/Swagger 3.0 Parser and Swift code generator
MIT License
627 stars 148 forks source link

oneOf does not generate cases when the type is object #302

Closed JanC closed 2 years ago

JanC commented 2 years ago

Hi, I noticed that the oneOf keyword seems to be ignored when the schema contains also the type: object:

In the below example, the SingleAnimal is taken from the spec.yaml but I added the type: object.

The generated code is a struct

public struct SingleAnimal: Codable, Equatable {
    public init() {}

    public init(from _: Decoder) throws {}
}

while I would expect it to be a enum

public enum SingleAnimal: Codable, Equatable {
    case cat(Cat)
    case dog(Dog)

    public init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: StringCodingKey.self)
        let discriminator: String = try container.decode("type")
        switch discriminator {
        case "Cat":
            self = .cat(try Cat(from: decoder))
        case "Dog":
            self = .dog(try Dog(from: decoder))
        case "cat":
            self = .cat(try Cat(from: decoder))
        case "dog":
            self = .dog(try Dog(from: decoder))
        case "woof":
            self = .dog(try Dog(from: decoder))
        default:
            throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Couldn't find type to decode with discriminator \(discriminator)"))
        }
    }
}
SingleAnimal:
  type: object   #This was added
  oneOf:
    - $ref: '#/components/schemas/Cat'
    - $ref: '#/components/schemas/Dog'
  discriminator:
    propertyName: type
    mapping:
      woof: '#/components/schemas/Dog'
      dog: '#/components/schemas/Dog'
      cat: '#/components/schemas/Cat'
Cat:
  allOf:
    - $ref: '#/components/schemas/Animal'
    - type: object
      properties:
        meows:
          type: boolean
Dog:
  allOf:
    - $ref: '#/components/schemas/Animal'
    - type: object
      properties:
        barks:
          type: boolean
Animal:
    type: object
    properties:
      animal:
        type: string
JanC commented 2 years ago

I believe it is due to this part when decoding the schema dictionary. If the schema parses as DataType we assume it's actually a datatype and don't check further for the allOf, oneOf and allOf.

The open api validation parses such a schema as a oneOf so it seems those specific types have priority over the type: object.

Would it make sense to change the parsing below and try first to parse the allOf, oneOf and allOf and only then the DataType?

This would be a bit of an assumption though that the composite keywords (oneOf, anyOf, allOf) have priority over the object type. I opened a ticket in the springdoc repo which causes such a yaml to be generated: https://github.com/springdoc/springdoc-openapi/issues/1589

https://github.com/yonaskolb/SwagGen/blob/7119a7b7abc79cdcfd179020cc0d81a81de22fb4/Sources/Swagger/Schema/Schema.swift#L57-L72

JanC commented 2 years ago

closed by PR