ferdikoomen / openapi-typescript-codegen

NodeJS library that generates Typescript or Javascript clients based on the OpenAPI specification
MIT License
2.86k stars 516 forks source link

Add support for `const` keyword #1834

Open robertadkins opened 10 months ago

robertadkins commented 10 months ago

I have a usecase where it would be helpful to support constant values via the const keyword.

Say we have an api spec containing some models like:

{
  "components": {
    "schemas": {
      "Animal": {
        "anyOf": [
          {
            "$ref": "#/components/schemas/Dog"
          },
          {
            "$ref": "#/components/schemas/Cat"
          }
        ]
      },
      "Dog": {
        "type": "object",
        "properties": {
          "type": {
            "const": "Dog"
          },
          "isPuppy": {
            "type": "boolean",
          }
        }
      },
      "Cat": {
        "properties": {
          "type": {
            "const": "Cat"
          },
          "isKitten": {
            "type": "boolean",
          }
        }
      }
    }
  }
}

In typescript, this should map to something like:

type Animal = Dog | Cat;
type Dog = {
  type: "Dog";
  isPuppy: boolean;
};
type Cat = {
  type: "Cat";
  isKitten: boolean;
};

This way, we can narrow the type in a useful way:

function isBaby(animal: Animal): boolean {
  switch(animal.type) {
    case "Dog":
      return animal.isPuppy;
    case "Cat":
      return animal.isKitten;
  }
}

However, openapi-typescript-codegen maps const values to any types, so the type information is lost.

mbergen commented 10 months ago

I don't see a spec including

"type": {
  "const": "Cat"
},

being compatible with the OpenAPI spec, where type is required to be a string. It would be weird to deviate the codegen to something that is not following the specification it is supposed to generate from, or am i missing something?

robertadkins commented 10 months ago

type is required to be a string.

Ah, sorry I've actually overloaded type here. In

"type": {
    "const": "Cat"
},

type is the name of a property on the Cat object. For clarity, we could give the property a different name, like id:

"id": {
    "const": "Cat"
},

The issue still applies here independent of the property name.

mbergen commented 10 months ago

That would still be an extension to the OpenAPI spec, or am i misunderstanding your proposal? As an alternative, did you try to use an enum with the possible values your subclasses can have as a type to handle this?

robertadkins commented 10 months ago

The OpenAPI spec includes the const keyword as of version 3.1 and was explicitly addressed as part of https://github.com/OAI/OpenAPI-Specification/pull/1977. From the spec:

The Schema Object allows the definition of input and output data types. These types can be objects, but also primitives and arrays. This object is a superset of the JSON Schema Specification Draft 2020-12.

For more information about the properties, see JSON Schema Core and JSON Schema Validation.

The JSON Schema Validation spec above defines the const keyword (alongside with enum and type as generic validation keywords).

Some other libraries already have support for const, e.g. openapi-typescript added support in https://github.com/drwpow/openapi-typescript/pull/831.

mbergen commented 10 months ago

I see, i just looked at the currently supported v3.0, not at v3.1, sorry.

robertadkins commented 10 months ago

Ah, I see! So only v3.0 is currently supported here. Any opposition to starting v3.1 support with this change? Adding const should be a non-breaking update to v3.0 parsing.

mbergen commented 10 months ago

I'm by no means opposed, but i'm also not the maintainer of this library.

keul commented 9 months ago

This would be great, in fact this is making this generator not usable with the SpatioTemporal Asset Catalogs standard, which uses a stac_version constant