scottie1984 / swagger-ui-express

Adds middleware to your express app to serve the Swagger UI bound to your Swagger document. This acts as living documentation for your API hosted from within your app.
MIT License
1.4k stars 225 forks source link

Not rendering with $refs #364

Closed thardy closed 7 months ago

thardy commented 7 months ago

I've got my open-api.yml spec working fine in document editors, but I can't get swagger-ui-express to render it correctly. I need some help.

Here are the links to my exact files... open-api.yml - https://github.com/thardy/kazuku/blob/feature/wranglingServerAndTests/server/docs/open-api.yml app.js - https://github.com/thardy/kazuku/blob/f4daba2e24d3e6fd547948e296ff09e273350536/server/src/app.js#L95C1-L95C1

Here is the structure of my files... image

I get a rendered page, but it doesn't have much on it. I get no errors, and the only clue I have is that the schemas show "$ref". It looks like this... image

My paths are declared like this...

paths:
  /auth/register:
    $ref: './paths/auth/auth-register.yml'
  /auth/request-token-using-refresh-token:
    $ref: './paths/auth/auth-request-token-using-refresh-token.yml'

and my schemas are declared like this...

components:
  schemas:
    $ref: './schemas/index.yml'

I figure it has something to do with the relative paths to my $refs. I REALLY like the modular way I've built this, but I also need it to work. Any help will be greatly appreciated.

dylthedev commented 7 months ago

If you have refs in your yaml, those will be loaded into your JSON. You need to use something between loading the yaml file and serving the JSON to resolve the references in the JSON, js-yaml doesn't do that. Something like json-refs would.

In your particular use case, this should work

import jsonRefs from 'json-refs';
// ...

// setup our swagger page
const openApiSpecPath = path.join(__dirname, '..', 'docs', 'open-api.yml');
const openApiSpecFile  = fs.readFileSync(openApiSpecPath, 'utf8');
const swaggerDocument = yaml.load(openApiSpecFile);

const resolvedSwaggerDocument = await jsonRefs.resolveRefs(swaggerDocument, {
    location: openApiSpecPath,
    loaderOptions: {
        processContent: function (res, callback) {
            callback(yaml.load(res.text)); // this callback is required to resolve those JSON references 
        }
    }
});

app.use('/api/swagger', swaggerUi.serve, swaggerUi.setup(resolvedSwaggerDocument.resolved));

Note you might not be set up properly to use top level await, so you may have to create your own async function.

thardy commented 7 months ago

That did it! Thank you!