swagger-cli icon indicating copy to clipboard operation
swagger-cli copied to clipboard

Bundle: option to keep all refs but turn them into internal refs

Open joffrey-bion opened this issue 5 years ago • 13 comments

The bundle command's current behaviour breaks the code generation in my current project.

Currently, with no special option, the bundle command inlines all $refs it finds on the first encounter, and then makes a reference to that local inline upon any subsequent encounter of the same reference.

For this example input:

main.yaml

swagger: '2.0'
info:
  version: 0.0.0
paths:
  /test1:
    get:
      parameters:
        - $ref: "./parameters.yaml#/parameters/param"
  /test2:
    get:
      parameters:
        - $ref: "./parameters.yaml#/parameters/param"

parameters.yaml

parameters:
  param:
    in: query
    name: myParam
    description: some demo parameter
    type: string
    pattern: '^[a-zA-Z]+$'
    required: true

The output I get from npx swagger-cli bundle main.yaml is the following:

swagger: '2.0'
info:
  version: 0.0.0
paths:
  /test1:
    get:
      parameters:
        - in: query
          name: myParam
          description: some demo parameter
          type: string
          pattern: '^[a-zA-Z]+$'
          required: true
  /test2:
    get:
      parameters:
        - $ref: '#/paths/~1test1/get/parameters/0'

When things get complicated, it can yield references like this:

$ref: '#/paths/~1analytics-ui/post/parameters/3/schema/items/properties/data/properties/page/properties/attributes'

And during code generation, this may turn into class names as long as this path, which is far from ideal.

It would be nice to have an option (e.g. --no-dereference) to preserve any reference, and simply bring the referenced declarations to the bundled file, but in a separate place within the file. This means that every reference will simply become a local declaration, but point to the same path.

Here is the output I would expect using this option on the same sample input that I provided:

bundle.yaml

swagger: '2.0'
info:
  version: 0.0.0
paths:
  /test1:
    get:
      parameters:
        - $ref: "#/parameters/param"
  /test2:
    get:
      parameters:
        - $ref: "#/parameters/param"

parameters:
  param:
    in: query
    name: myParam
    description: some demo parameter
    type: string
    pattern: '^[a-zA-Z]+$'
    required: true

Is there a way to achieve this currently?

joffrey-bion avatar May 13 '19 15:05 joffrey-bion

Would love to have this feature too!

mgrzechocinski avatar May 24 '19 09:05 mgrzechocinski

I would also like to have this feature. Specifically for OpenAPI 3, It would be great to have an option where bundle takes the referenced components and combines them in a components section in a bundled file, updating the original $ref that pointed to <file>#<componentPath> to point to #<componentPath> in the combined file.

aaldredge avatar Aug 06 '19 18:08 aaldredge

A +1 on this, since I have a circular reference on my project and the code generation breaks if I don't use --dereference, which I have to because of the circular ref.

lorthirk avatar Sep 12 '19 07:09 lorthirk

Thanks @lorthirk. Using --dereference fix my issues with circular ref. Having this feature would be really awesome !

stephanebachelier avatar Nov 05 '19 21:11 stephanebachelier

@lorthirk @aaldredge @mgrzechocinski @joffrey-bion it seems that it already exists as long as you manage to avoid circular references. I add forgotten to add some schemas before the paths sections. Adding them before the path sections remove the circular references are they are already defined in the bundled schema.

Now mystery of references are rewritten using schema references : From $ref: ../../components/responses/index.yaml#/Unauthenticated, the reference is changed to $ref: '#/components/responses/Unauthenticated' in the bundled file.

And the Unauthenticated is existing only in the #/components/responses section.

stephanebachelier avatar Nov 05 '19 21:11 stephanebachelier

@stephanebachelier thanks for the tag.

I tried with the latest version (2.3.4) using the command swagger-cli bundle schemas/specs/all.yaml -t yaml -o schemas/resolved/all.yaml and I am still seeing the reference inlined and then referenced later with a $ref to the inlined occurrence. This results in refs such as:

- $ref: '#/paths/~1v1~1my~1path/get/parameters/0'

and this beauty

- $ref: '#/paths/~1v1~1my~1other-path/get/responses/200/content/application~1json/schema/allOf/1/properties/data/items/oneOf/0/properties/dataPoint/allOf/0'

aaldredge avatar Nov 11 '19 18:11 aaldredge

+1, very important feature. With --dereference we unable to generate valid client specification.

There is no semantic names for schemas:

  /random:
    get:
      summary: todo.
      description: todo.
      security:
        - bearerAuth: []
      responses:
        '200':
          description: Successful result.
          content:
            application/json:
              schema:
                type: object
                required:
                  - categories
                properties:
                  categories:
                    type: object
                    required:
                      - name
                    properties:
                      name:
                        type: string

Bogdaan avatar Jan 27 '20 15:01 Bogdaan

Would be great to have a solution for this! Running into the same issue.

theaxel avatar Mar 02 '20 17:03 theaxel

In our projects we only have a few shared schemas. A workaround we've been using because of this problem is to avoid code like this:

swagger: '2.0'
info:
  version: 0.0.0
paths:
  /test1:
    get:
      parameters:
        - $ref: "./parameters.yaml#/parameters/param"
  /test2:
    get:
      parameters:
        - $ref: "./parameters.yaml#/parameters/param"

and use code like this instead:

swagger: '2.0'
info:
  version: 0.0.0
paths:
  /test1:
    get:
      parameters:
        - $ref: "#/parameters/param"
  /test2:
    get:
      parameters:
        - $ref: "#/parameters/param"
parameters:
  param:
    $ref: "./parameters.yaml#/parameters/param"

This gets bundled into:

swagger: '2.0'
info:
  version: 0.0.0
paths:
  /test1:
    get:
      parameters:
        - $ref: "#/parameters/param"
  /test2:
    get:
      parameters:
        - $ref: "#/parameters/param"

parameters:
  param:
    in: query
    name: myParam
    description: some demo parameter
    type: string
    pattern: '^[a-zA-Z]+$'
    required: true

which works with our code generators but takes some extra lines.

AlbinoDrought avatar Nov 10 '20 22:11 AlbinoDrought

Hello there,

I am waiting to have ref internal or to ignore hasardous generation: #/paths/~1users~1address~1%7Bid%7D/get/responses/200/content/application~1json/schema/properties/data

During this time, I am coding some split string things to get what I want in my original file to get internal components to bundle a valid file.

Thank in advance

MaxDesplanches avatar Nov 18 '20 22:11 MaxDesplanches

+

bu4ak avatar Mar 01 '21 09:03 bu4ak

Looks related to https://github.com/APIDevTools/swagger-parser/issues/127

aleskovets avatar May 19 '21 18:05 aleskovets

Copying from https://github.com/APIDevTools/swagger-parser/issues/127#issuecomment-922634697


The obvious -- if annoying -- workaround is to put components first, and reference everything there.

Example input

example.yml

openapi: "3.0.3"
components: # reference everything here
  schemas:
    a: { $ref: "./schema/a.yml" }
    b: { $ref: "./schema/b.yml" }
info:
  title: Example
  version: 0.0.0
paths:
  /a:
    get:
      responses:
        "200":
           content:
             application/json:
               schema: { $ref: "./schema/a.yml" }
           description: Success
  /b:
    get:
      responses:
        "200":
          content:
            application/json:
              schema: { $ref: "./schema/b.yml" }
          description: Success

schema/a.yml

properties:
  aName: { type: string }
  b: { $ref: "./b.yml" }

schema/b.yml

properties:
  bName: { type: string }
Example output
swagger-cli bundle example.yml

yields

openapi: 3.0.3
components:
  schemas:
    a:
      properties:
        aName:
          type: string
        b:
          $ref: '#/components/schemas/b'
    b:
      properties:
        bName:
          type: string
info:
  title: Example
  version: 0.0.0
paths:
  /a:
    get:
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/a'
          description: Success
  /b:
    get:
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/b'
          description: Success

pauldraper avatar Sep 20 '21 04:09 pauldraper