Openapi-generator: [BUG][Typescript-Fetch] Incorrect toJSON & fromJSONTyped functions when using oneOf

Created on 3 Feb 2020  路  7Comments  路  Source: OpenAPITools/openapi-generator

Bug Report Checklist

  • [x] Have you provided a full/minimal spec to reproduce the issue?
  • [X] Have you validated the input using an OpenAPI validator (example)?
  • [X] What's the version of OpenAPI Generator used?
  • [X] Have you search for related issues/PRs?
  • [X] What's the actual output vs expected output?
Description

For a property defined using oneOf, invalid methods are generated for <Model>FromJSONTyped and for <Model>ToJSON:

See the nextUrl field below:

/**
 * 
 * @export
 * @interface Todos
 */
export interface Todos {
    /**
     * List of links to next pages of results in a series.   The first element in the array is the exact next page after the current record, etc. 
     * @type {string | UrlList}
     * @memberof Todos
     */
    nextUrl?: string | UrlList;
}

export function TodosFromJSON(json: any): Todos {
    return TodosFromJSONTyped(json, false);
}

export function TodosFromJSONTyped(json: any, ignoreDiscriminator: boolean): Todos {
    if ((json === undefined) || (json === null)) {
        return json;
    }
    return {
        // THIS IS INVALID TYPESCRIPT
        'nextUrl': !exists(json, 'next_url') ? undefined : string | UrlListFromJSON(json['next_url']),
    };
}

export function TodosToJSON(value?: Todos | null): any {
    if (value === undefined) {
        return undefined;
    }
    if (value === null) {
        return null;
    }
    return {
        // THIS IS INVALID TYPESCRIPT
        'next_url': string | UrlListToJSON(value.nextUrl),
    };
}

Expected

For both of those fields, I would expect a typeof check to decide what to do:

'next_url': typeof value.nextUrl === 'string' ? value.nextUrl : UrlListToJSON(value.nextUrl),
openapi-generator version

4.2.3 via

yarn list v1.21.0
鈹斺攢 @openapitools/[email protected]
OpenAPI declaration file content or url
openapi: 3.0.0
info:
  title: Todo API
  description: A reference API description for a Todo service
  version: 1.0.0
servers:
  - url: http://localhost:8000/v1
    description: Generic HTTP
paths:
  /todos:
    get:
      summary: List the available todo tasks
      operationId: ListTodos
      responses:
        '200':
          description: a list of Todos
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Todos'
components:
  schemas:
    urlValue:
      type: string
      description: A single url.
    urlList:
      type: array
      description: A list of urls.
      items:
        type: string
    Todos:
      type: object
      properties:
        next_url:
          description: |
            List of links to next pages of results in a series.

             The first element in the array is the exact next page after the current record, etc.
          oneOf:
            - $ref: '#/components/schemas/urlValue'
            - $ref: '#/components/schemas/urlList'
Command line used for generation

./node_modules/@openapitools/openapi-generator-cli/bin/openapi-generator generate -g typescript-fetch -i ./openapi.yaml -o .

CONFIG: - "generateAliasAsModel": true

If generateAliasAsModel is false (default) then the generated Todos model is also incorrect:

export interface Todos {
    /**
     * List of links to next pages of results in a series.   The first element in the array is the exact next page after the current record, etc. 
     * @type {string | Array}
     * @memberof Todos
     */
    nextUrl?: string | Array;  // THIS IS INVALID TYPESCRIPT
}
TypeScript Bug

Most helpful comment

I've been tinkering around with this for a couple of evenings now. I was able to get something working for top level anyOf/oneOf types but there is not enough data provided by the core to build out the proper support for inline types. That happens to be most of the use case for our current spec. It looks like this outstanding PR get's most of the way if not all of the way there. https://github.com/OpenAPITools/openapi-generator/pull/3162

All 7 comments

馃憤 Thanks for opening this issue!
馃彿 I have applied any labels matching special text in your issue.

The team will review the labels and make any necessary changes.

@eriktim any thought on whats going wrong here?

@jamesopti @fantapop the oneOf construct is far from mature here. The following changes are needed (even though the specification file is not incorrect):

  • The oneOf cannot be nested, so Todos should not be an object with a field but just the oneOf;
  • urlValue and urlList must be objects with in this case only one field.

Thank you for the hints here. Looking closer at the open api spec, I see that the generated typescript is more like anyOf. It looks like oneOf is intended to be an exclusive Or. anyOf, however, seems to fail in the same way.

@fantapop You are right. Though anyOf would also allow a mixture of types (e.g. two fields from type A and one field from type B). I personally favor the use case of defining union/sum types.
To fully support the exclusivity, I guess the generator should apply strict de-serialisation first.

I recently had a similar conversation with one of the maintainers of the https://github.com/lukeautry/tsoa project which generates an open api spec from typescript definitions. They are now using anyOf as their implementation of union which I think makes sense. It's very important to me that the generated typescript types from the open api spec are compatible with the input types that generate them in the tsoa project. Some of the nuances of these types are a little over my head. @eriktim Do you agree that anyOf would translate best to a straight typescript union? I was thinking oneOf could be something like what's arrived at here: https://timhwang21.gitbook.io/index/programming/typescript/xor-type . Although, I'm not really seeing how TSOA would translate something like a oneOf from their end unless some more prescriptive type or syntax was released by the typescript project or if unless there was a documented type name that could be used for that specific purpose. Regardless, it feels like getting the union definition working is a very important step in bringing this template along. I wonder if the true nature of this bug is really, how should unions work vs how should oneOf be translated.

I've been tinkering around with this for a couple of evenings now. I was able to get something working for top level anyOf/oneOf types but there is not enough data provided by the core to build out the proper support for inline types. That happens to be most of the use case for our current spec. It looks like this outstanding PR get's most of the way if not all of the way there. https://github.com/OpenAPITools/openapi-generator/pull/3162

Was this page helpful?
0 / 5 - 0 ratings