swagger-jsdoc: Cannot reference yaml alias if anchor is in other comment

I would like to use a yaml anchor to define in my swagger doc an object that is used in multiple places. If I have a comment like this in one file:

/**
 * @swagger
 * '/helloworld':
 *   get:
 *     summary: The helloworld API
 *     description: This is a description.
 *     security: []
 *     responses:
 *       200:
 *         description: OK
 *         content:
 *           application/json:
 *             schema:
 *               $ref: '#/components/schemas/HelloWorld'
 *     x-amazon-apigateway-integration: *default-integration
 */

And I have in my definition file:

x-amazon-apigateway-integrations:
  default-integration: &default-integration
    type: object
    x-amazon-apigateway-integration:
      httpMethod: POST
      passthroughBehavior: when_no_match
      type: aws_proxy
      uri: 'arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:123456789:function:helloworldlambda/invocations'

I get the following output when running swagger-jsdoc:

'/helloworld':
  get:
    summary: The helloworld API
    description: This is a description.
    security: []
    responses:
      200:
        description: OK
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/HelloWorld'
    x-amazon-apigateway-integration: *default-integration -------------- Pay attention at this place

/Users/proberts/src/hello-world/node_modules/swagger-jsdoc/lib/index.js:32
    throw new Error(err);
    ^

Error: YAMLException: unidentified alias "default-integration" at line 13, column 58:
     ... ntegration: *default-integration
                                         ^
    at module.exports.options (/Users/proberts/src/hello-world/node_modules/swagger-jsdoc/lib/index.js:32:11)
    at createSpecification (/Users/proberts/src/hello-world/node_modules/swagger-jsdoc/bin/swagger-jsdoc.js:39:31)
    at fs.readFile (/Users/proberts/src/hello-world/node_modules/swagger-jsdoc/bin/swagger-jsdoc.js:170:10)
    at FSReqWrap.readFileAfterClose [as oncomplete] (fs.js:511:3)

If I add the anchor to within the same swagger-jsdoc comment, it works as expected. I’m guessing the problem is that lib/helpers/filterJsDocComments.js is loading each comment as individual yaml documents.

I can help with a fix, if there’s a good idea on how to solve this. Maybe a new optional anchors file, or root definition property, that can be concatenated to every swagger-jsdoc comment in lib/helpers/filterJsDocComments.js?

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Comments: 16 (12 by maintainers)

Most upvoted comments

Hi to all subscribed and interested in the issue 👋

I’ve been attempting to solve this issue and I’m sharing latest progress although I haven’t solved it yet. It’s been quite some time since the last communication here, but I needed to get the code base in shape before being able to properly approach the issue.

If you’re still interested in helping you can see this line in the latest version of the pull request https://github.com/Surnet/swagger-jsdoc/blob/9092962ea442807a3bda512dbaae4d4070edeb64/src/specification.js#L176 At this point I’ve prepared the things to have an array of data ready to be parsed by a yaml parser.

The current parse used is js-yaml and I’ve tried all of its methods for parsing attemping document per document or concatenated single file. Neither of the methods I tried has yielded a working solution.

The ideas I have at the moment for moving forward in the series of attempts:

  • try another package such https://github.com/eemeli/yaml/
  • try adding support for a new supplementary annotation such as @swagger to organize documents containing references

To reproduce the issue, follow along the breaking test or put the following in the above-mentioned line before the iterator

ndb example/v2/app.js

Hi @kalinchernev , thanks for the quick response. Here’s a modified version of what you posted:

index.js:

const express = require("express");
const swaggerJSDoc = require("swagger-jsdoc");

const port = process.env.PORT || 3000;
const app = express();

/**
 * @swagger
 * '/helloworld':
 *   get:
 *     summary: The helloworld API
 *     description: This is a description.
 *     security: []
 *     responses:
 *       200:
 *         description: OK
 *         content:
 *           application/json:
 *             schema:
 *               $ref: '#/components/schemas/HelloWorld'
 *     x-amazon-apigateway-integration: *default-integration
 */
app.get("/", () => {});

const swaggerDefinition = {
  openapi: "3.0.0",
  info: {
    title: "AWS API Gateway",
    version: "1.0.0"
  }
};

const options = {
  swaggerDefinition,
  apis: ["./*.js", "./x-amazon-apigateway-integrations.yaml"]
};

const swaggerSpec = swaggerJSDoc(options);

app.get("/api", (req, res) => {
  res.send(swaggerSpec);
});

app.listen(port, () => console.log(`http://localhost:${port}`));

x-amazon-apigateway-integrations.yaml:

x-amazon-apigateway-integrations:
  default-integration: &default-integration
    type: object
    x-amazon-apigateway-integration:
      httpMethod: POST
      passthroughBehavior: when_no_match
      type: aws_proxy
      uri: 'arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:123456789:function:helloworldlambda/invocations'

Running node index.js results in:

[paul]:[/tmp/test-swagger-jsdoc]$ npm start

> test-swagger-jsdoc@1.0.0 start /tmp/test-swagger-jsdoc
> node index.js

'/helloworld':
  get:
    summary: The helloworld API
    description: This is a description.
    security: []
    responses:
      200:
        description: OK
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/HelloWorld'
    x-amazon-apigateway-integration: *default-integration -------------- Pay attention at this place

/tmp/test-swagger-jsdoc/node_modules/swagger-jsdoc/lib/index.js:32
    throw new Error(err);
    ^

Error: YAMLException: unidentified alias "default-integration" at line 13, column 58:
     ... ntegration: *default-integration
                                         ^
    at module.exports.options (/tmp/test-swagger-jsdoc/node_modules/swagger-jsdoc/lib/index.js:32:11)
    at Object.<anonymous> (/tmp/test-swagger-jsdoc/index.js:38:21)
    at Module._compile (module.js:652:30)
    at Object.Module._extensions..js (module.js:663:10)
    at Module.load (module.js:565:32)
    at tryModuleLoad (module.js:505:12)
    at Function.Module._load (module.js:497:3)
    at Function.Module.runMain (module.js:693:10)
    at startup (bootstrap_node.js:188:16)
    at bootstrap_node.js:609:3
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! test-swagger-jsdoc@1.0.0 start: `node index.js`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the test-swagger-jsdoc@1.0.0 start script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /home/paul/.npm/_logs/2019-02-16T21_48_59_868Z-debug.log

I believe it is failing at this line because each jsdoc comment is parsed as individual yaml documents. The comment contains an alias to an anchor that is defined somewhere else, so jsYaml throws an “unidentified alias” exception.

My project has several express mappings across different files, and I would like to avoid copy-pasting the same 7 lines of yaml for each one.