Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Example not working with TS project because of swagger-schema-official types bug #269

Closed
fox1t opened this issue Jul 16, 2020 · 15 comments
Closed

Comments

@fox1t
Copy link
Member

fox1t commented Jul 16, 2020

🐛 Bug Report

The example provided in the README.md doesn't work with typescript because Schema type doesn't have .

This is a swagger-schema-official types bug and i am writing it here just for reference.

To Reproduce

Just copy-paste the example in a TS project and you will get:

No overload matches this call.
  Overload 2 of 3, '(plugin: FastifyPluginAsync<SwaggerOptions, Server>, opts?: (RegisterOptions & FastifyStaticSwaggerOptions) | (RegisterOptions & FastifyDynamicSwaggerOptions) | (() => (RegisterOptions & FastifyStaticSwaggerOptions) | (RegisterOptions & FastifyDynamicSwaggerOptions)) | undefined): FastifyInstance<...> & PromiseLike<...>', gave the following error.
    Argument of type 'FastifyPlugin<SwaggerOptions>' is not assignable to parameter of type 'FastifyPluginAsync<SwaggerOptions, Server>'.
      Type 'FastifyPluginCallback<SwaggerOptions, Server>' is not assignable to type 'FastifyPluginAsync<SwaggerOptions, Server>'.

Digging more into this i found that leaving just one of the nullable fields displays the correct error.
Object literal may only specify known properties, and 'nullable' does not exist in type 'Schema'

this is the Schema definition:

export type BaseSchema = {
  type?: ParameterType;
  format?: string;
  title?: string;
  description?: string;
  default?: any;
  multipleOf?: number;
  maximum?: number;
  exclusiveMaximum?: boolean;
  minimum?: number;
  exclusiveMinimum?: boolean;
  maxLength?: number;
  minLength?: number;
  pattern?: string;
  maxItems?: number;
  minItems?: number;
  uniqueItems?: boolean;
  maxProperties?: number;
  minProperties?: number;
  enum?: any[];
  items?: Schema | Schema[];
};

export interface Schema extends BaseSchema {
  $ref?: string;
  allOf?: Schema[];
  additionalProperties?: Schema | boolean;
  properties?: { [propertyName: string]: Schema };
  discriminator?: string;
  readOnly?: boolean;
  xml?: XML;
  externalDocs?: ExternalDocs;
  example?: any;
  required?: string[];
}
fastify.register(swagger, {
  routePrefix: '/documentation',
  swagger: {
    info: {
      title: 'Test swagger',
      description: 'testing the fastify swagger api',
      version: '0.1.0',
    },
    externalDocs: {
      url: 'https://swagger.io',
      description: 'Find more info here',
    },
    host: 'localhost',
    schemes: ['http'],
    consumes: ['application/json'],
    produces: ['application/json'],
    tags: [
      { name: 'user', description: 'User related end-points' },
      { name: 'code', description: 'Code related end-points' },
    ],
    definitions: {
      User: {
        type: 'object',
        required: ['id', 'email'],
        properties: {
          id: { type: 'string', format: 'uuid' },
          firstName: { type: 'string', nullable: true },
          lastName: { type: 'string', nullable: true },
          email: { type: 'string', format: 'email' },
        },
      },
    },
    securityDefinitions: {
      apiKey: {
        type: 'apiKey',
        name: 'apiKey',
        in: 'header',
      },
    },
  },
  exposeRoute: true,
})

Expected behavior

No error at all.

fastify.register(swagger, {
  routePrefix: '/documentation',
  swagger: {
    info: {
      title: 'Test swagger',
      description: 'testing the fastify swagger api',
      version: '0.1.0',
    },
    externalDocs: {
      url: 'https://swagger.io',
      description: 'Find more info here',
    },
    host: 'localhost',
    schemes: ['http'],
    consumes: ['application/json'],
    produces: ['application/json'],
    tags: [
      { name: 'user', description: 'User related end-points' },
      { name: 'code', description: 'Code related end-points' },
    ],
    definitions: {
      User: {
        type: 'object',
        required: ['id', 'email'],
        properties: {
          id: { type: 'string', format: 'uuid' },
          firstName: { type: 'string',  },
          lastName: { type: 'string',  },
          email: { type: 'string', format: 'email' },
        },
      },
    },
    securityDefinitions: {
      apiKey: {
        type: 'apiKey',
        name: 'apiKey',
        in: 'header',
      },
    },
  },
  exposeRoute: true,
})

Your Environment

  • node version: 12
  • fastify version: >=3.0.0
  • os: macOS
@mcollina
Copy link
Member

Would you like to send a Pull Request to address this issue? Remember to add unit tests.

@fox1t
Copy link
Member Author

fox1t commented Jul 16, 2020

Actually I am still digging into this. It seems that nullable: true is an OpenAPI v3 spec so it is wrong to use it here since fastify-swagger is based on v2. What do you think? Maybe a proper fix is just to remove nullable: true from the example.

@mcollina
Copy link
Member

it's also one of the things that is mostly requested in this module.

@benediktdertinger
Copy link
Contributor

Hi guys, I just upgraded to fastify v3 to use fastify-swagger. The problem seems not to be solved. Any ideas on how to solve this?

@fox1t
Copy link
Member Author

fox1t commented Sep 2, 2020

@benediktdertinger are you using nullable keyword?

@benediktdertinger
Copy link
Contributor

@fox1t thanks for your fast reply! If I'm using the default setup from the README I'm getting the error you described.

What seems to be interesting: If I remove the section swaggerPluginOptions.swagger.definitions.User from the settings object the error is gone but the created HTML page (exposed via http://0.0.0.0:1234/documentation/static/index.html) is blank (the HTML structure is created but no body content was added). I've been trying to use the example route from the README and also placed some additional schema details in my routes (although they already included some). I also removed my previous routes and only used the example one + placed the registration of the swagger plugin at the beginning and the end of plugin registration sequence. It always returns a blank page.

My setup:

"dependencies": {
    "ajv": "^6.12.4",
    "ajv-errors": "^1.0.1",
    "bcryptjs": "^2.4.3",
    "bluebird": "^3.7.2",
    "crypto-random-string": "^3.2.0",
    "csv-parse": "^4.12.0",
    "fastify": "^3.3.0",
    "fastify-auth": "^1.0.1",
    "fastify-basic-auth": "^1.0.1",
    "fastify-compress": "^3.3.0",
    "fastify-cors": "^4.1.0",
    "fastify-helmet": "^5.0.1",
    "fastify-jwt": "^2.1.3",
    "fastify-multer": "^2.0.2",
    "fastify-plugin": "^2.3.3",
    "fastify-swagger": "^3.3.0",
    "got": "^11.5.2",
    "highland": "^2.13.5",
    "http-errors": "^1.8.0",
    "lodash": "^4.17.20",
    "make-promises-safe": "^5.1.0",
    "mathjs": "^7.2.0",
    "moment": "^2.27.0",
    "mongodb": "^3.6.0",
    "mongoose": "^5.10.2",
    "ms": "^2.1.2",
    "qs": "^6.9.4",
    "sharp": "^0.26.0",
    "tap": "^14.10.8",
    "ts-mongoose": "0.0.21",
    "yargs": "^15.4.1"
  },
  "devDependencies": {
    "@types/ajv-errors": "^1.0.2",
    "@types/bcryptjs": "^2.4.2",
    "@types/bluebird": "^3.5.32",
    "@types/highland": "^2.12.10",
    "@types/http-errors": "^1.8.0",
    "@types/lodash": "^4.14.161",
    "@types/mathjs": "^6.0.5",
    "@types/mongoose": "^5.7.36",
    "@types/ms": "^0.7.31",
    "@types/node": "^14.6.2",
    "@types/qs": "^6.9.4",
    "@types/sharp": "^0.25.1",
    "@types/yargs": "^15.0.5",
    "@typescript-eslint/eslint-plugin": "^4.0.1",
    "@typescript-eslint/parser": "^4.0.1",
    "eslint": "^7.8.1",
    "eslint-config-airbnb-base": "^14.2.0",
    "eslint-plugin-import": "^2.22.0",
    "nodemon": "^2.0.4",
    "ts-node": "^9.0.0",
    "typescript": "^4.0.2"
  }

@fox1t
Copy link
Member Author

fox1t commented Sep 3, 2020

@benediktdertinger User definition in the example is not working because of the nullable keyword:

 firstName: { type: 'string', nullable: true },
 lastName: { type: 'string', nullable: true },

Removing these makes the example work again. It is only a TS issue because of the missing types on the swagger side.

Can you open a new issue and add a repro repository for the blank page?

@fox1t
Copy link
Member Author

fox1t commented Sep 3, 2020

@mcollina since nullable: true is only v3 spec and this module, as of today, implements only v2, I think it would be better to remove this from the example, since it makes the example itself worng.

@mcollina
Copy link
Member

mcollina commented Sep 3, 2020

Go for it

@benediktdertinger
Copy link
Contributor

@fox1t yes, I already did this (as described above). If I remove the User definition the error is gone and the HTML page is created but it is blank. Any idea on this? Should I open another Issue?

@benediktdertinger
Copy link
Contributor

@benediktdertinger User definition in the example is not working because of the nullable keyword:

 firstName: { type: 'string', nullable: true },
 lastName: { type: 'string', nullable: true },

Removing these makes the example work again. It is only a TS issue because of the missing types on the swagger side.

Can you open a new issue and add a repro repository for the blank page?

@fox1t If I remove firstName and lastName from the example I get:

 Overload 1 of 3, '(plugin: FastifyPluginCallback<SwaggerOptions, Server>, opts?: FastifyRegisterOptions<SwaggerOptions>): FastifyInstance<...> & PromiseLike<...>', gave the following error.
    Type '{ $id: string; type: "object"; required: string[]; properties: { id: { type: "string"; format: string; }; email: { type: "string"; format: string; }; }; }' is not assignable to type 'Schema'.
      Object literal may only specify known properties, and '$id' does not exist in type 'Schema'.
  Overload 2 of 3, '(plugin: FastifyPluginAsync<SwaggerOptions, Server>, opts?: FastifyRegisterOptions<SwaggerOptions>): FastifyInstance<...> & PromiseLike<...>', gave the following error.
    Argument of type 'FastifyPlugin<SwaggerOptions>' is not assignable to parameter of type 'FastifyPluginAsync<SwaggerOptions, Server>'.
      Type 'FastifyPluginCallback<SwaggerOptions, Server>' is not assignable to type 'FastifyPluginAsync<SwaggerOptions, Server>'.
  Overload 3 of 3, '(plugin: FastifyPluginCallback<SwaggerOptions, Server> | FastifyPluginAsync<SwaggerOptions, Server> | Promise<...> | Promise<...>, opts?: FastifyRegisterOptions<...>): FastifyInstance<...> & PromiseLike<...>', gave the following error.
    Type '{ $id: string; type: "object"; required: string[]; properties: { id: { type: "string"; format: string; }; email: { type: "string"; format: string; }; }; }' is not assignable to type 'Schema'.
      Object literal may only specify known properties, and '$id' does not exist in type 'Schema'.

By removing $id: 'User', as well, everything is working fine and I get the intended documentation.

@benediktdertinger
Copy link
Contributor

@fox1t I also found the problem regarding the blank page (due to helmet security policy) and opened a new feature proposal here: #294

@fox1t
Copy link
Member Author

fox1t commented Sep 3, 2020

@benediktdertinger would you mind to make a PR to fix the example? Just remove the broken parts. After it, we will handle the black page issue.

@benediktdertinger
Copy link
Contributor

Hi @fox1t I did so in #296

@climba03003
Copy link
Member

closing it as swagger-schema-official is removed in dependencies. #328 #333

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants