Missing Mapping In OneOf With Discriminator
Introduction
When working with OpenAPI specifications, it's essential to ensure that the generated code accurately reflects the intended behavior. However, in some cases, the generated code may not match the expected output. This article explores a specific issue related to the use of oneOf
with a discriminator in OpenAPI specifications, where a mapping is missing from the generated code.
The Issue
The problem arises when using the oneOf
keyword in conjunction with a discriminator in an OpenAPI specification. The discriminator is used to determine which schema to use based on a specific property. However, when the order of the schemas in the oneOf
array is changed, the generated code may not include all the expected mappings.
Example Configuration
The following is an example OpenAPI configuration that demonstrates the issue:
"/tasks/chat": {
"post": {
"summary": "Create Chat Task",
"description": "Create a new chat task.",
"operationId": "create_chat_task_tasks_chat_post",
"requestBody": {
"content": {
"application/json": {
"schema": {
"oneOf": [
{
"$ref": "#/components/schemas/StandaloneChatRequestParams"
},
{
"$ref": "#/components/schemas/MapReduceChatRequestParams"
}
],
"title": "Request",
"discriminator": {
"propertyName": "processing_mode",
"mapping": {
"standalone": "#/components/schemas/StandaloneChatRequestParams",
"map": "#/components/schemas/MapReduceChatRequestParams",
"reduce": "#/components/schemas/MapReduceChatRequestParams"
}
}
}
}
},
"required": true
},
In this example, the oneOf
array contains two schemas: StandaloneChatRequestParams
and MapReduceChatRequestParams
. The discriminator is used to determine which schema to use based on the value of the processing_mode
property.
Generated Code
When the OpenAPI specification is processed using the @hey-api/openapi-ts
library, the following code is generated:
export type CreateChatTaskTasksChatPostData = {
body:
| ({
processing_mode?: "standalone";
} & StandaloneChatRequestParams)
| ({
processing_mode?: "map";
} & MapReduceChatRequestParams);
path?: never;
query?: never;
url: "/tasks/chat";
};
As can be seen, the generated code is missing the reduce
mapping, which is expected to be included based on the oneOf
array.
Reproducible Example
To reproduce this issue, you can create a new OpenAPI specification with the following content:
openapi: 3.0.0
info:
title: Chat API
description: API for creating chat tasks
version: 1.0.0
paths:
/tasks/chat:
post:
summary: Create Chat Task
description: Create a new chat task.
operationId: create_chat_task_tasks_chat_post
requestBody:
content:
application/json:
schema:
oneOf:
- $ref: '#/components/schemas/StandaloneChatRequestParams'
- $ref: '#/components/schemas/MapReduceChatRequestParams'
title: Request
discriminator:
propertyName: processing_mode
mapping:
standalone: '#/components/schemas/StandaloneChatRequestParams'
map: '#/components/schemas/MapReduceChatRequestParams'
reduce: '#/components/schemas/MapReduceChatRequestParams'
components:
schemas:
StandaloneChatRequestParams:
type: object
properties:
foo:
type: string
MapReduceChatRequestParams:
type: object
properties:
bar:
type: string
Then, process the OpenAPI specification using the @hey-api/openapi-ts
library and observe the generated code.
Conclusion
In conclusion, the issue of missing mappings in oneOf
with a discriminator is a known problem in OpenAPI specifications. The generated code may not include all the expected mappings when the order of the schemas in the oneOf
array is changed. This article has demonstrated the issue using a reproducible example and provided a solution to the problem.
Recommendations
To avoid this issue, it's recommended to:
- Use a consistent order for the schemas in the
oneOf
array. - Use a discriminator with a single mapping property.
- Verify the generated code to ensure that all expected mappings are included.
Q: What is the issue with missing mapping in oneOf with discriminator?
A: The issue arises when using the oneOf
keyword in conjunction with a discriminator in an OpenAPI specification. The discriminator is used to determine which schema to use based on a specific property. However, when the order of the schemas in the oneOf
array is changed, the generated code may not include all the expected mappings.
Q: What is the cause of this issue?
A: The cause of this issue is the way the oneOf
keyword is processed by the OpenAPI specification parser. When the parser encounters the oneOf
keyword, it creates a union type that includes all the schemas in the array. However, when the discriminator is used, the parser only includes the schemas that match the specified property. If the order of the schemas is changed, the parser may not include all the expected mappings.
Q: How can I reproduce this issue?
A: To reproduce this issue, you can create a new OpenAPI specification with the following content:
openapi: 3.0.0
info:
title: Chat API
description: API for creating chat tasks
version: 1.0.0
paths:
/tasks/chat:
post:
summary: Create Chat Task
description: Create a new chat task.
operationId: create_chat_task_tasks_chat_post
requestBody:
content:
application/json:
schema:
oneOf:
- $ref: '#/components/schemas/StandaloneChatRequestParams'
- $ref: '#/components/schemas/MapReduceChatRequestParams'
title: Request
discriminator:
propertyName: processing_mode
mapping:
standalone: '#/components/schemas/StandaloneChatRequestParams'
map: '#/components/schemas/MapReduceChatRequestParams'
reduce: '#/components/schemas/MapReduceChatRequestParams'
components:
schemas:
StandaloneChatRequestParams:
type: object
properties:
foo:
type: string
MapReduceChatRequestParams:
type: object
properties:
bar:
type: string
Then, process the OpenAPI specification using the @hey-api/openapi-ts
library and observe the generated code.
Q: How can I fix this issue?
A: To fix this issue, you can use a consistent order for the schemas in the oneOf
array. You can also use a discriminator with a single mapping property. Additionally, you can verify the generated code to ensure that all expected mappings are included.
Q: What are the best practices for using oneOf with discriminator?
A: The best practices for using oneOf
with discriminator are:
- Use a consistent order for the schemas in the
oneOf
array. - Use a discriminator with a single mapping property.
- Verify the generated code to ensure that all expected mappings are included.
- Avoid using
oneOf
with a large number of schemas. - Use a more specific discriminator property instead of a generic one.
Q: Can I use oneOf with multiple discriminators?
A: No, you cannot use oneOf
with multiple discriminators. The oneOf
keyword is used to create a union type that includes all the schemas in the array. If you use multiple discriminators, the parser will not be able to determine which schema to use.
Q: Can I use oneOf with a discriminator and a union type?
A: Yes, you can use oneOf
with a discriminator and a union type. However, you need to be careful when using this combination, as it can lead to unexpected behavior.
Q: How can I troubleshoot this issue?
A: To troubleshoot this issue, you can:
- Verify the OpenAPI specification to ensure that it is correct.
- Check the generated code to ensure that it includes all the expected mappings.
- Use a debugger to step through the code and identify the issue.
- Consult the documentation for the OpenAPI specification parser to ensure that you are using it correctly.
- Reach out to the community for help and support.