Surnet / swagger-jsdoc

Generates swagger/openapi specification based on jsDoc comments and YAML files.
MIT License
1.69k stars 228 forks source link

node_modules/swagger-jsdoc/src/specification.js:141 for (const definition of Object.keys(annotation[property])) Cannot convert undefined or null to object #289

Open daniel-aluna opened 2 years ago

daniel-aluna commented 2 years ago

Describe the bug

when I run npm run start to test my api docs in localhost:3100 I get the following error:

Not all input has been taken into account at your final specification.
Here's the report:

 YAMLSemanticError: Implicit map keys need to be on a single line at line 3, column 5:

    tags:[Auth]
    ^^^^^^^^^^^…
,YAMLSyntaxError: All collection items must start at the same column at line 3, column 5:

    tags: [Auth]
    ^^^^^^^^^^^^…
,YAMLSemanticError: Implicit map keys need to be followed by map values at line 4, column 5:

    tags:[Auth]
    ^^^^^^^^^^^
,YAMLSemanticError: Implicit map keys need to be on a single line at line 3, column 5:

    tags:[Auth]
    ^^^^^^^^^^^…
,YAMLSemanticError: Implicit map keys need to be on a single line at line 3, column 5:

    tags:[Auth]
    ^^^^^^^^^^^…
,YAMLSemanticError: Implicit map keys need to be followed by map values at line 4, column 5:

    tags:[Auth]
    ^^^^^^^^^^^
,YAMLSemanticError: Implicit map keys need to be followed by map values at line 4, column 5:

    tags:[Auth]
    ^^^^^^^^^^^
,YAMLSyntaxError: All collection items must start at the same column at line 2, column 3:

  post:
  ^^^^^…

YAMLSemanticError: Nested mappings are not allowed in compact mappings at line 4, column 18:

    description: To create invitation for organization.
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^…

YAMLSemanticError: Implicit map keys need to be on a single line at line 4, column 18:

    description: To create invitation for organization.
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^…
,YAMLSemanticError: Nested mappings are not allowed in compact mappings at line 19, column 22:

        description: Some properties are missing: pui, noteType, noteText, isPr…
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^…

/Users/danielcortes/Aluna-Projects/nimbus/node_modules/swagger-jsdoc/src/specification.js:141
    for (const definition of Object.keys(annotation[property])) {
                                    ^

TypeError: Cannot convert undefined or null to object
    at Function.keys (<anonymous>)
    at organize (/Users/danielcortes/Aluna-Projects/nimbus/node_modules/swagger-jsdoc/src/specification.js:141:37)
    at build (/Users/danielcortes/Aluna-Projects/nimbus/node_modules/swagger-jsdoc/src/specification.js:278:7)
    at Object.module.exports [as default] (/Users/danielcortes/Aluna-Projects/nimbus/node_modules/swagger-jsdoc/src/lib.js:31:10)
    at SwaggerConfig.registerSwaggerPage (/Users/danielcortes/Aluna-Projects/nimbus/dist/common/swagger.config.js:53:52)
    at Object.<anonymous> (/Users/danielcortes/Aluna-Projects/nimbus/dist/app.js:157:46)
    at Module._compile (node:internal/modules/cjs/loader:1108:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1137:10)
    at Module.load (node:internal/modules/cjs/loader:988:32)
    at Function.Module._load (node:internal/modules/cjs/loader:828:14)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:76:12)

I am wondering if it is due to this configuration:

registerSwaggerPage(app: express.Application, listeners: [(entry: SwaggerEndPointInformationDto) => void]) {
    // registerSwaggerPage(app: express.Application) {
    this.built = true;

    const packageJson = JSON.parse(readFileSync('./package.json').toString());
    const swaggerOptions = {
      definition: {
        openapi: '3.0.0',
        info: {
          title: packageJson.name,
          version: packageJson.version,
        }
      },
      apis: [
        './dist/**/*.js',
      ],
    };
    // const swaggerSpec: {paths: never;} = swaggerJsdoc(swaggerOptions);
    // @ts-ignore
    const swaggerSpec: { paths: string; } = swaggerJsdoc(swaggerOptions);
    const swaggerUiOptions = {
      explorer: true,
    };

    // add to components.schemas
    this.models.forEach(model => {
      const swaggerModel = m2s(model)
      // @ts-ignore
      swaggerSpec.components.schemas.push(swaggerModel);
    });

    // add routes
    app._router.stack.filter((e: { route: never; }) => e.route).forEach((element: any) => {
      console.log(element)
      // if (element?.route?.path?.startsWith('/')) {
      //   const httpPath: string = element.route.path
      //   // @ts-ignore
      //   if (!swaggerSpec.paths[httpPath]) {
      //     // @ts-ignore
      //     swaggerSpec.paths[httpPath] = {}
      //   }
      //   // @ts-ignore
      //   const pathInfo = swaggerSpec.paths[httpPath];
      //   for (const e in Object.keys(element.route.methods)) {
      //     const httpMethod = Object.keys(element.route.methods)[e]
      //     // console.log(element.route.methods[httpMethod])
      //     if (element.route.methods[httpMethod]) {
      //       if(!pathInfo[httpMethod]) {
      //         // @ts-ignore
      //         pathInfo[httpMethod] = {
      //           description: "This is a description",
      //           content: {
      //             // "application/json": {
      //             //     "schema":
      //             // }
      //           }
      //         }
      //       }

      //       // const eventDto = new SwaggerEndPointInformationDto(httpMethod, httpPath)
      //       // listeners.forEach((fn: (entry: SwaggerEndPointInformationDto) => void) => fn(eventDto))
      //     }
      //   }
      // }
    });

    app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec, swaggerUiOptions));
    console.log(JSON.stringify(swaggerSpec, null, 2))

    //app._router.stack.filter(e => e.route)
  }

Even though it was working before with the above configuration.

To Reproduce

  1. Write a registerSwaggerPage() similar to how you see it above inside of swagger.config.ts file.
  2. Run your boilerplate swagger application with a similar setup to this:
/**
     * @openapi
     * /api/v2/patients/{patientId}/notes:
     *   get:
     *     tags: [Patients]
     *     description: get notes for a patient.
     *     responses:
     *       200:
     *         description: get notes for a patient.
     *         content:
     *           application/json:
     *             schema:
     *             $ref: '#/components/schemas/ViewNoteDto'
     *       403:
     *         description: Only 'application/json'. incoming content is supported..
     *         content:
     *           application/json:
     *             schema:
     *             $ref: '#/components/schemas/BaseErrorDto' 
     *       500:
     *         description: A server error. The returned object contains the exact nature of the error.
     *         content:
     *           application/json:
     *             schema:
     *             $ref: '#/components/schemas/BaseErrorDto'          
     */
    this.app.get(p().api.v2.patients.$patientId.notes.$url, [
      authMiddleware.verifyJWT,
      patientsMiddleware.createPatientContext,
      patientsMiddleware.collectPatientId,
      notesController.findNotesByPui
    ]);

Expected behavior

I expect that when I run npm run start I do not get the above error.

Screenshots If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

Additional context Add any other context about the problem here.

daniloab commented 2 years ago

hi there @daniel-aluna

Can you provide a tiny repo where the error can be reproduced and help us to understand what is happening?

Thank you.

itsnoa04 commented 1 year ago

Ive had the same issue, for me it was a syntax error in the js doc. wish there was a way to identify them better like maybe a vscode plugin for swagger-jsdoc.

might work on it after i'm done with my current project