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

Swagger Docs generated do not show added schemas as models #225

Closed
chill-cod3r opened this issue Feb 13, 2020 · 17 comments · Fixed by #459
Closed

Swagger Docs generated do not show added schemas as models #225

chill-cod3r opened this issue Feb 13, 2020 · 17 comments · Fixed by #459

Comments

@chill-cod3r
Copy link

chill-cod3r commented Feb 13, 2020

Feature Request

While fastify-swagger is great for schemas attached to routes, I also would expect to be able to leverage it for displaying the models independent of the routes (usually shown at the bottom of the generated swagger-ui). When I call fastify.addSchema on one of my reusable schemas, I would expect it to show up as a model.

To Reproduce

Steps to reproduce the behavior:

  1. generate a boilerplate fastify app with fastify-cli

Paste your code here:
2. change the app.js file to the following (basically copy / pasted from fastify-swagger + my example of trying to use the schema to display a model

"use strict";

const path = require("path");
const AutoLoad = require("fastify-autoload");

module.exports = function(fastify, opts, next) {
  // Place here your custom code!

  // Do not touch the following lines

  // This loads all plugins defined in plugins
  // those should be support plugins that are reused
  // through your application
  fastify.register(AutoLoad, {
    dir: path.join(__dirname, "plugins"),
    options: Object.assign({}, opts)
  });

  // This loads all plugins defined in services
  // define your routes in one of these
  fastify.register(AutoLoad, {
    dir: path.join(__dirname, "services"),
    options: Object.assign({}, opts)
  });

  fastify.register(require("fastify-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" }
      ],
      securityDefinitions: {
        apiKey: {
          type: "apiKey",
          name: "apiKey",
          in: "header"
        }
      }
    },
    exposeRoute: true
  });

  const schemaIWantToAdd = {
    $id: "User",
    type: "object",
    required: ["id", "firstName", "lastName", "email"],
    properties: {
      id: { type: "string", format: "uuid" },
      firstName: { type: "string" },
      lastName: { type: "string" },
      email: { type: "string", format: "email" }
    }
  };

  // trying to use the schema as a model below
  fastify.addSchema(schemaIWantToAdd);

  fastify.ready(err => {
    if (err) throw err;
    fastify.swagger();
  });

  fastify.get(
    "/some-route",
    {
      schema: {
        description: "post some data",
        tags: ["user", "code"],
        summary: "qwerty",
        params: {
          type: "object",
          properties: {
            id: {
              type: "string",
              description: "user id"
            }
          }
        },
        body: {
          type: "object",
          properties: {
            hello: { type: "string" },
            obj: {
              type: "object",
              properties: {
                some: { type: "string" }
              }
            }
          }
        },
        response: {
          201: {
            description: "Successful response",
            type: "object",
            properties: {
              hello: { type: "string" }
            }
          }
        },
        security: [
          {
            apiKey: []
          }
        ]
      }
    },
    async (req, reply) => {
      return { hello: "world" };
    }
  );

  // Make sure to call next when done
  next();
};

Expected behavior

I would expect the added schema would show up as a model at the bottom of the generated swagger-ui

Paste the results here:

image

Your Environment

  • node version: 12
  • fastify version: >=2.0.0
  • os: Mac
@mcollina
Copy link
Member

How should the model be included in swagger file? We are literally doing nothing about those right now.
Would you like to send a PR adding support for them?

@chill-cod3r
Copy link
Author

Yes, I would propose a path to mapping those to “definitions”. Sounds like a good chance for me to dive in, I’ll get started and see what I can come up with,

@mcollina
Copy link
Member

mcollina commented Feb 13, 2020 via email

@chill-cod3r
Copy link
Author

Okay, so upon initial inspection, I definitely see a path to this by hooking into the fastify.addSchema function inside the plugin, essentially adding it to definitions and then continuing on with running the regular addSchema functionality, however I'm wondering if this feature is needed.

After looking through the code, I missed something super obvious that could possibly just be covered in a slight documentation update (Swagger gurus - not me 🤣 probably would never need it). The update (at least in my mind) would be to simply mention that the opts.swagger configuration required to initialize the fastify-swagger plugin has a definitions field that does exactly what I want it to.

image

It definitely solves the issue I'm having as models would not need to be dynamic (at least not that I can think of), and the implementation of this feature could even lead to confusion as to why it's necessary in the first place.

I realize you may have known all of this already, and might think there is value in this feature still. If so, I would love to do it! If you would let me know your thoughts when you have a chance, that would help a lot. If we decide the feature may not be worth it, I might try to make a small PR to include an example definition in the documentation.

@mcollina
Copy link
Member

I don't know really, if you'd like to contribute this, we can definitely do it behind an option.

@chill-cod3r
Copy link
Author

Okay, I'm going to think on the use case a bit more and circle back to this. In the meantime, I'll separately submit a PR to add an example definitions to the readme.

@mcollina
Copy link
Member

mcollina commented Feb 13, 2020 via email

@SkeLLLa
Copy link
Contributor

SkeLLLa commented Feb 18, 2020

@wolfejw86
You can reference to this implementation https://github.com/SkeLLLa/fastify-oas/blob/master/lib/openapi/constructor.js#L109. And get schemas like https://github.com/SkeLLLa/fastify-oas/blob/master/lib/openapi/index.js#L5. Basically simple copy-paste should work, you just need to put them into proper place for swagger v2.

@chill-cod3r
Copy link
Author

Yeah I agree, it's a little more work to get it back to the definitions configuration, but not much. My 2 cents is that this issue could be closed since it's relatively easy to achieve the desired outcome with the code as is.
I also put in a PR that got merged to essentially "remind" folks that the way to do it is to put it in definitions - #227

@Fusix
Copy link

Fusix commented Aug 17, 2020

I am having huge problems referencing a model saved in definitions.

definitions: {
    user: {
        type: 'object',
        properties: {
            surname: {type: 'string'},
            lastname: {type: 'string'},
            birthday: {type: 'string', format: 'date'},
            email: {type: 'string'},
            street: {type: 'string'},
            city: {type: 'string'},
            zip: {type: 'number'},
            phone: {type: 'string'},
            mobile: {type: 'string'},
            password: {type: 'string'}
        }
    }
}

How do I reference this model from my route?

$ref: '#/definitions/user' is giving me following error

'Failed building the validation schema for POST: /users, due to error can't resolve reference #/definitions/user from id #'

@Alex-Ferreli
Copy link

Any news on this issue?

@brandondoran
Copy link

brandondoran commented Jan 28, 2021

Setting definitions in swagger options works for simple schemas but when you have $refs in the schema they seem to get replaced inline with what the $ref was referring to. So you get duplicated type definitions nested within a parent (in addition to a top level type). This is reflected in the models in swagger UI. Also this is bad if you generate types from the swagger spec.

@letmaik
Copy link

letmaik commented Jul 16, 2021

Similar issue here, although it's nearly working. When you use the $ref-way as described in https://www.fastify.io/docs/v2.2.x/Validation-and-Serialization/#adding-a-shared-schema then the schema automatically gets added to definitions and properly referenced. But the big caveat is that it auto-generates a name for the definition, "def-0". I also haven't tested nested references yet. Is there any way to specify the names that the definitions should get?

@letmaik
Copy link

letmaik commented Jul 20, 2021

Looks like the def-<x> generated definition names come from https://github.com/Eomm/json-schema-resolver and apparently there's no way to influence that. There's a PR from 2020 Eomm/json-schema-resolver#4 but the library doesn't really seem to be maintained anymore.

@Eomm
Copy link
Member

Eomm commented Jul 20, 2021

It is, but I don't have a timeframe to work on that feature right now

If you would like to revamp that PR it is appreciated

@Eomm
Copy link
Member

Eomm commented Aug 26, 2021

'Failed building the validation schema for POST: /users, due to error can't resolve reference #/definitions/user from id

I'm a bit late here.

Anyway to explain: if you define schemas in your swagger options, fastify is not aware of them so you can't use in your route's schema.

For sure, it is doable to arrange a PR to call: fastify.addSchema() when the swaggerUi settings have them: this is the only way to let Fastify be aware of the presence of these schemas.

Is there any way to specify the names that the definitions should get?

Working on it.
The first simple solution is to define a title, so you will not see any def-0:

{
    $id: "User",
    title: "SHOW ME ON SWAGGER UI",  // <-------- here
    type: "object",
    required: ["id", "firstName", "lastName", "email"],
    properties: {
      id: { type: "string", format: "uuid" },
      firstName: { type: "string" },
      lastName: { type: "string" },
      email: { type: "string", format: "email" }
    }
  }

@madshargreave
Copy link

Setting definitions in swagger options works for simple schemas but when you have $refs in the schema they seem to get replaced inline with what the $ref was referring to. So you get duplicated type definitions nested within a parent (in addition to a top level type). This is reflected in the models in swagger UI. Also this is bad if you generate types from the swagger spec.

@brandondoran I've been tripped up by this behavior as well. Did you manage to find a solution?

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

Successfully merging a pull request may close this issue.

9 participants