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

Bug - swagger-ui-express is not rendering the content of API documentation #333

Closed mahdiHash closed 1 year ago

mahdiHash commented 1 year ago

Swagger-ui-express v4.6.0. Openapi v3.0.0.. Express v4.18.2. Brave Browser v1.47.186 (Chromium v109.0.5414.119).

I'm using Swagger-ui-express (without JSDOC) in my Express.js app to write documentation for my API. Here's the routing and middleware code (I use swagger.josn instead of writing comments):

const swaggerUI = require('swagger-ui-express');
const swaggerDoc = require('./swagger.json');

app.use('/apidocs', swaggerUI.serve, swaggerUI.setup(swaggerDoc));

When I go to the route specified for reading the documentation, the page is blank and there's nothing rendered:

docs rendering in my browser

As you can see, the route and the swagger-ui-express middleware are working (there's "Swagger UI" and its icon on the tab's title), but I have no idea why it's not rendering anything.

There's also an error in the browser console:

the error in console

I'm using OpenAPI (Swagger) Editor VSCode extension to see the preview of documentation and it's rendering OK, which means everything is syntactically correct:

docs rendering with VSCode extension

I sent a request via Postman and I got this:

<!-- HTML for static distribution bundle build -->
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Swagger UI</title>
    <link rel="stylesheet" type="text/css" href="./swagger-ui.css">
    <link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
    <link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
    <style>
        html {
            box-sizing: border-box;
            overflow: -moz-scrollbars-vertical;
            overflow-y: scroll;
        }

        *,
        *:before,
        *:after {
            box-sizing: inherit;
        }

        body {
            margin: 0;
            background: #fafafa;
        }
    </style>
</head>

<body>

    <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
        style="position:absolute;width:0;height:0">
        <defs>
            <symbol viewBox="0 0 20 20" id="unlocked">
                <path
                    d="M15.8 8H14V5.6C14 2.703 12.665 1 10 1 7.334 1 6 2.703 6 5.6V6h2v-.801C8 3.754 8.797 3 10 3c1.203 0 2 .754 2 2.199V8H4c-.553 0-1 .646-1 1.199V17c0 .549.428 1.139.951 1.307l1.197.387C5.672 18.861 6.55 19 7.1 19h5.8c.549 0 1.428-.139 1.951-.307l1.196-.387c.524-.167.953-.757.953-1.306V9.199C17 8.646 16.352 8 15.8 8z">
                </path>
            </symbol>

            <symbol viewBox="0 0 20 20" id="locked">
                <path
                    d="M15.8 8H14V5.6C14 2.703 12.665 1 10 1 7.334 1 6 2.703 6 5.6V8H4c-.553 0-1 .646-1 1.199V17c0 .549.428 1.139.951 1.307l1.197.387C5.672 18.861 6.55 19 7.1 19h5.8c.549 0 1.428-.139 1.951-.307l1.196-.387c.524-.167.953-.757.953-1.306V9.199C17 8.646 16.352 8 15.8 8zM12 8H8V5.199C8 3.754 8.797 3 10 3c1.203 0 2 .754 2 2.199V8z" />
            </symbol>

            <symbol viewBox="0 0 20 20" id="close">
                <path
                    d="M14.348 14.849c-.469.469-1.229.469-1.697 0L10 11.819l-2.651 3.029c-.469.469-1.229.469-1.697 0-.469-.469-.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-.469-.469-.469-1.228 0-1.697.469-.469 1.228-.469 1.697 0L10 8.183l2.651-3.031c.469-.469 1.228-.469 1.697 0 .469.469.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c.469.469.469 1.229 0 1.698z" />
            </symbol>

            <symbol viewBox="0 0 20 20" id="large-arrow">
                <path
                    d="M13.25 10L6.109 2.58c-.268-.27-.268-.707 0-.979.268-.27.701-.27.969 0l7.83 7.908c.268.271.268.709 0 .979l-7.83 7.908c-.268.271-.701.27-.969 0-.268-.269-.268-.707 0-.979L13.25 10z" />
            </symbol>

            <symbol viewBox="0 0 20 20" id="large-arrow-down">
                <path
                    d="M17.418 6.109c.272-.268.709-.268.979 0s.271.701 0 .969l-7.908 7.83c-.27.268-.707.268-.979 0l-7.908-7.83c-.27-.268-.27-.701 0-.969.271-.268.709-.268.979 0L10 13.25l7.418-7.141z" />
            </symbol>

            <symbol viewBox="0 0 24 24" id="jump-to">
                <path d="M19 7v4H5.83l3.58-3.59L8 6l-6 6 6 6 1.41-1.41L5.83 13H21V7z" />
            </symbol>

            <symbol viewBox="0 0 24 24" id="expand">
                <path d="M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z" />
            </symbol>

        </defs>
    </svg>

    <div id="swagger-ui"></div>

    <script src="./swagger-ui-bundle.js"> </script>
    <script src="./swagger-ui-standalone-preset.js"> </script>
    <script src="./swagger-ui-init.js"> </script>

    <style>
        .swagger-ui .topbar .download-url-wrapper {
            display: none
        }

        undefined
    </style>
</body>

</html>

I opened swagger-ui-init.js file in the browser dev tools and I got the same code as the response I got in Postman. I think the swaggerUI middleware is putting wrong code inside swagger-ui-init.js.
Could this problem be fixed? Am I doing anything wrong here?

mahdiHash commented 1 year ago

Apparently, the problem was using localhost instead of 127.0.0.1! I don't know why this happened.

tfrancois commented 1 year ago

I am having the same or similar issue - not rendering in express and I have tried localhost and 127.0.0.1. Incidentially, my specific error is:

SyntaxError: JSON.parse: unexpected character at line 2 column 1 of the JSON data
mahdiHash commented 1 year ago

I am having the same or similar issue - not rendering in express and I have tried localhost and 127.0.0.1. Incidentially, my specific error is:

SyntaxError: JSON.parse: unexpected character at line 2 column 1 of the JSON data

Since it's a SyntaxError, there's probably something wrong with your .json file.

tfrancois commented 1 year ago

I figured out what the issue was! This is important! Make sure the Content-Type is text/html (sent via headers from Express) - the trick for me was to explicitly move the route to the highest order possible and prior to me setting the standard 'application/json' Content-Type that I needed for the rest of the express back-end. It's amazing how such a little change solved such a major issue. Hope it helps.