OpenAPITools / OpenAPITools/openapi-generator
[BUG][Typescript] Incorrect response type handling for oneOf strategy
Open
Nobody has claimed this yet.
Issue: Bug
- Dominant language
- Java
- Stars
- 26.8k
- Forks
- 7.7k
- PR merge metrics
- PR metrics pending
Description
Bug Report Checklist
- Have you provided a full/minimal spec to reproduce the issue?
- Have you validated the input using an OpenAPI validator (example)?
- Have you tested with the latest master to confirm the issue still exists?
- Have you searched for related issues/PRs?
- What's the actual output vs expected output?
- [Optional] Sponsorship to speed up the bug fix or feature request (example)
Description
- Is there a way to not have a wrapper object as an input parameter and instead just take an union type?
- The return types are correct but it seems not to be handled correctly, a bug perhaps?
- If everything works as intended how can I change my schema so the generated client has a method that can parse the response and type it correctly?
openapi-generator version
5.1.0
OpenAPI declaration file content or url
specs.yaml
openapi: 3.0.1
info:
title: Sample API
description: Optional multiline or single-line description in [CommonMark](http://commonmark.org/help/) or HTML.
version: 0.1.9
servers:
- url: http://api.example.com/v1
description: Optional server description, e.g. Main (production) server
- url: http://staging-api.example.com
description: Optional server description, e.g. Internal staging server for testing
paths:
/pets:
post:
requestBody:
content:
application/json:
schema:
oneOf:
- $ref: '#/components/schemas/Cat'
- $ref: '#/components/schemas/Dog'
discriminator:
propertyName: pet_type
mapping:
obj1: '#/components/schemas/Cat'
obj2: '#/components/schemas/Dog'
responses:
'200':
description: Created
content:
application/json:
schema:
oneOf:
- $ref: '#/components/schemas/Cat'
- $ref: '#/components/schemas/Dog'
discriminator:
propertyName: pet_type
mapping:
obj1: '#/components/schemas/Cat'
obj2: '#/components/schemas/Dog'
components:
schemas:
Pet:
type: object
required:
- pet_type
properties:
pet_type:
type: string
discriminator:
propertyName: pet_type
Dog:
type: object
allOf:
- $ref: '#/components/schemas/Pet'
- type: object
properties:
bark:
type: boolean
breed:
type: string
enum: [Dingo, Husky, Retriever, Shepherd]
Cat:
type: object
allOf:
- $ref: '#/components/schemas/Pet'
- type: object
properties:
hunts:
type: boolean
age:
type: integer
Generation Details
java -jar openapi-generator-cli.jar generate -i specs.yaml -g typescript-fetch -o tsclient/
Output
...
export interface PetsPostRequest {
catDog?: Cat | Dog;
}
/**
*
*/
export class DefaultApi extends runtime.BaseAPI {
/**
*/
async petsPostRaw(requestParameters: PetsPostRequest): Promise<runtime.ApiResponse<Cat | Dog>> {
const queryParameters: any = {};
const headerParameters: runtime.HTTPHeaders = {};
headerParameters['Content-Type'] = 'application/json';
const response = await this.request({
path: `/pets`,
method: 'POST',
headers: headerParameters,
query: queryParameters,
body: Cat | DogToJSON(requestParameters.catDog),
});
return new runtime.JSONApiResponse(response, (jsonValue) => Cat | DogFromJSON(jsonValue));
}
/**
*/
async petsPost(requestParameters: PetsPostRequest): Promise<Cat | Dog> {
const response = await this.petsPostRaw(requestParameters);
return await response.value();
}
Expected, something like
async petsPostRaw(pet: Cat | Dog | undefined ): Promise<runtime.ApiResponse<Cat | Dog>> {
const queryParameters: any = {};
const headerParameters: runtime.HTTPHeaders = {};
headerParameters['Content-Type'] = 'application/json';
const response = await this.request({
path: `/pets`,
method: 'POST',
headers: headerParameters,
query: queryParameters,
body: pet.petType === 'Cat' ? CatToJSON() : pet.petType === 'Dog' ? DogToJSON() : undefined,
});
return new runtime.JSONApiResponse(response,
(jsonValue) => {
const typedValue =
pet.petType === 'Cat' ? CatFromJSON(jsonValue)
: pet.petType === 'Dog' ? DogFromJSON(jsonValue)
: undefined;
if(!typedValue){
throw new Error(`No type matching "${pet.petType}" found`);
}
return typedValue;
});
}
/**
*/
async petsPost(pet: Cat | Dog): Promise<Cat | Dog> {
const response = await this.petsPostRaw(pet);
return await response.value();
}
Related issues/PRs
- Probably more than one regarding oneOf, anyOf, allOf
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reproducing the issue with the supplied specs.yaml and the typescript-fetch generation command. Compare the generated petsPost request and response handling with the expected Cat | Dog behavior, then trace the oneOf serialization and deserialization entry points. Done means the generated client handles the union without the incorrect wrapper and preserves the expected response typing.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- openapi, typescript
- Domain
- api, tooling
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 30/100