Enums Mappings in OpenAPI
OpenAPI does not directly support mapping enum keys to values, so if we had an C# enum:
enum Direction {
Up = 0;
Down = 1;
Left = 2;
Right = 3;
}
The equivalent OpenAPI json file would be missing the enum keys. To supply them, we can use the x-enum-varnames
extension. This extension allows us to provide additional metadata for our enums, such as the variable names used in our code.
Here’s how we can represent the Direction
enum from our C# example in an OpenAPI JSON file:
{
"components": {
"schemas": {
"Direction": {
"type": "integer",
"enum": [0, 1, 2, 3],
"x-enum-varnames": ["Up", "Down", "Left", "Right"]
}
}
}
}
Explanation
type
: The type is set to integer because the enum values in C# are integers.enum
: This array contains the possible integer values of the enum.x-enum-varnames
: This is a custom extension that lists the variable names corresponding to each enum value. This extension is not part of the official OpenAPI specification but is commonly used to provide additional context or metadata.
Conclusion
While OpenAPI does not natively support key-value mappings for enums, using extensions like x-enum-varnames
provides a flexible way to include additional metadata.
Client generators like openapi-generator-cli can use the extension to provide a key<>value mapping for the generated enums.
And even when a tool doesn’t directly support it, we could do some post-processing to generate the enum types:
const extractEnums = (openApiDoc: OpenAPIObject) => {
const schemas = openApiDoc.components?.schemas;
if (!schemas) return {};
const enumConstants = {} as Record<string, string>;
for (const [key, schema] of Object.entries(schemas)) {
if ("enum" in schema && "x-enum-varnames" in schema) {
const enumValues = schema.enum as number[];
const enumNames = schema["x-enum-varnames"] as string[];
const enumMap = enumNames.reduce((acc, name, index) => {
acc[name] = enumValues[index];
return acc;
}, {} as Record<string, number>);
const enumKey = key.replaceAll(".", "_");
enumConstants[key] = `
export const ${enumKey} = {
${enumNames.map((name) => `${name}: ${enumMap[name]}`).join(",\n")}
} as const;
`;
}
}
return `export namespace enums {
${Object.values(enumConstants).join("\n")}
}`;
}