openapi-typescript-codegen icon indicating copy to clipboard operation
openapi-typescript-codegen copied to clipboard

Sub-refs in external refs results in incorrect and broken imports in generated models

Open caseyfw opened this issue 3 years ago • 4 comments

Using a ref to refer to an object in a secondary file, that also uses refs to refer to other sibling objects results in strange incorrect imports in generated models.

For example, given the following spec:

# spec.yaml
components:
  schemas:
    LocalParent:
      $ref: './types.yaml#/components/schemas/Parent'

and the following secondary file:

# types.yaml
components:
  schemas:
    Parent:
      type: object
      properties:
        childA:
          $ref: '#/components/schemas/Child'
        childB:
          $ref: '#/components/schemas/Child'
    Child:
      type: string

Results in the following model with an import referencing a non-existent file:

# LocalParent.ts
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */

import type { LocalParent_properties_childA } from './LocalParent_properties_childA';

export type LocalParent = {
    childA?: string;
    childB?: LocalParent_properties_childA;
};

I'd like to resolve this myself, but have no idea where to start - I looked into the ref parser, but it seems to be returning a correct inventory. If you could nudge me in the right direction, I'm happy to do the legwork.

Thanks @ferdikoomen !

caseyfw avatar Feb 12 '22 09:02 caseyfw

After further investigation, I'm now sus on the remapping that occurs in the json-schema-ref-parser - it seems to dereference external refs differently to internal ones, and returns $ref pointers to specific fields rather than inventory entities. It might be correct for that project, but isn't handled correctly by the getModel function that isn't expecting a $ref to a field.

Would a potential solution be to add another branch to the if (definition.$ref) case in getModel to handle this? I feel like the answer is probably no, because by this time the model in question has already been dereferenced and remapped by json-schema-ref-parser and isn't available.

I feel like the solution is probably in json-schema-ref-parser. Add some mechanism to stop it remapping externals so differently? Not sure 🤷

caseyfw avatar Feb 13 '22 10:02 caseyfw

+1 I'm getting the same issue with nested referenced schemas.

ritchieanesco avatar Feb 20 '22 23:02 ritchieanesco

@caseyfw @ritchieanesco this sounds like a json-schema-ref-parser issue. Did you try to reproduce the result there. You should be able to do something like this in a simple NodeJS script:

const RefParser = require('json-schema-ref-parser');

const file = 'mySpec.json';

RefParser.bundle(file, file, {}).then(spec => {
    console.log(spec);
});

And see the resulting spec file (dereferenced and remapped)

Docs for the bundle method: https://apitools.dev/json-schema-ref-parser/docs/ref-parser.html#bundleschema-options-callback

ferdikoomen avatar Feb 25 '22 10:02 ferdikoomen