#Swagger - Can't load docs page

45 messages · Page 1 of 1 (latest)

round ferry
#

Good morning, I've been bashing my head on this problem for two days now.
I want to serve a swagger page on my APIs but the page is all white and when i check the logs i can see that it fails to load css and js files, it can't find them.

GET http://localhost:3000/docs/swagger-ui.css net::ERR_ABORTED 404 (Not Found)
GET http://localhost:3000/docs/swagger-ui-bundle.js net::ERR_ABORTED 404 (Not Found)
GET http://localhost:3000/docs/swagger-ui-standalone-preset.js net::ERR_ABORTED 404 (Not Found)
Uncaught ReferenceError: SwaggerUIBundle is not defined
    at window.onload (swagger-ui-init.js:121:7)

these are the versions i'm using:

"@nestjs/swagger": "^11.0.3",
"@nestjs/core": "^11.0.0",
"helmet": "^8.0.0",

I added a screenshot of my main.ts i don't have enough available characters on discord.

Is there something I'm doing wrong, thanks in advance?

marble fieldBOT
#

This message has been acknowledged by @round ferry, <t:1739010180:R>

mild sonnet
#

import { NestFactory } from '@nestjs/core';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import { AppModule } from './app.module';

async function bootstrap() {
const app = await NestFactory.create(AppModule);

const config = new DocumentBuilder()
.setTitle('API Docs')
.setDescription('API documentation for my service')
.setVersion('1.0')
.build();

const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('docs', app, document); // Ensure this is correctly set

await app.listen(3000);
}
bootstrap();

#

then, plz check if helmet is blocking static files

#

i think you are using helmet which is great for security, but it might be blocking swagger's assets

#

so i'd like to say to you have to try disabling csp temporarily to see if it fixes the issue

#

like this

#

import helmet from 'helmet';

async function bootstrap() {
const app = await NestFactory.create(AppModule);

app.use(helmet({
contentSecurityPolicy: false, // Disable CSP to allow Swagger assets
}));

const config = new DocumentBuilder()
.setTitle('API Docs')
.setDescription('API documentation for my service')
.setVersion('1.0')
.build();

const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('docs', app, document);

await app.listen(3000);
}
bootstrap();

#

if this fixes it, you can reenable csp later with proper script-src and style-src rules

round ferry
rustic citrus
#

@round ferry , just for the sake of my own debugging purposes, can you comment out your CORS section, and let me know if it loads without that configured?

#

Secondly, instead of your conditional loading for loading the API docs, can you just put the:

loadOpenApi

outside of it for this debugging test?

round ferry
#

Sorry been quite busy in these days:

async function bootstrap() {
  initSentry();
  const logger = new GeorgeLogger('Main');
  const app = await NestFactory.create(AppModule, {
    logger: createLoggerModule('Has George Read - API'),
  });

  app.use(json({ limit: '100kb' }));

  app.enableVersioning({
    defaultVersion: '1',
    type: VersioningType.URI,
  });

  logger.log('OpenAPI Docs Enabled');
  loadOpenApi(app, 'docs');

  app.useGlobalPipes(
    new ValidationPipe({
      always: true,
      transform: true,
    })
  );

  const { PORT = 3000 } = process.env;

  app.enableShutdownHooks();

  await app.listen(PORT, () => {
    logger.log(`App Running at port ${PORT}`);
  });

  Sentry.setupExpressErrorHandler(app);
}
bootstrap();

function loadOpenApi(app: INestApplication, path: string) {
  const config = new DocumentBuilder()
    .setTitle('We Road Demo')
    .setDescription('The We Road API description')
    .setVersion('1.0')
    .build();

  const document = SwaggerModule.createDocument(app, config);

  SwaggerModule.setup(path, app, document);
}

#

no luck

#

still blank page

#

could webpack be the reason?

#
module.exports = function (options) {
  return {
    ...options,
    devtool: 'source-map',
    externals: [
      {
        sqlite3: 'sqlite3',
        pg: 'pg',
        oracledb: 'oracledb',
        'pg-query-stream': 'pg-query-stream',
        mysql: 'mysql',
        tedious: 'tedious',
        'better-sqlite3': 'better-sqlite3',
        libsql: 'libsql',
        'mariadb/callback': 'mariadb/callback',
      },
    ],
  };
};
mild sonnet
#

so since you've already tried disabling CSP with Helmet, the issue might be related to webpack

#

so, just you can try adding this to your webpack config

#

externalsPresets: { node: true }

round ferry
#

i just looked in the console and the files were not loaded:

mild sonnet
#

alos, make sure static assets are being served correctly by nestjs

#

you can add this in your main.ts just to check

#

app.useStaticAssets(join(__dirname, '..', 'public'));

round ferry
#

useStaticAssets could not exist?

mild sonnet
#

if it still doesnt work, try setting the swagger path to the root like just SwaggerModule.setup('/', app, document); to rule out any routing conflicts

round ferry
#

oh i have to install the module okay

#

lemme try rq

#

tried everything, except the useStaticAssets, when i install it nad insert it in the import i get a fastify error, when i use express

mild sonnet
#

so you are using fastify?

round ferry
#

nope i'm using express

#

but when i use the serve-static module, i receive an error telling me he can't find fastify module

mild sonnet
#

ah, i see

#

so since you are using express, but it's mentioning fastify, it seems like there might be a conflict in the way nestjs or another module is handling the http adapter

#

just..., to make sure you are fully using express and not fastify, make sure you've explicitly specified the express adapter when creating the app

#

i mean, when you create the nestjs app, make sure to specify the express adapter like this...

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import * as serveStatic from 'serve-static';
import { join } from 'path';
import { ExpressAdapter } from '@nestjs/platform-express';

async function bootstrap() {
  const app = await NestFactory.create(AppModule, new ExpressAdapter());  // Explicitly using Express

  // Serve static assets
  app.use(serveStatic(join(__dirname, '..', 'node_modules', '@nestjs/swagger', 'dist')));

  const config = new DocumentBuilder()
    .setTitle('API Docs')
    .setDescription('The API description')
    .setVersion('1.0')
    .build();

  const document = SwaggerModule.createDocument(app, config);
  SwaggerModule.setup('docs', app, document);

  await app.listen(3000);
}

bootstrap();
#

also check your nestjs version

round ferry
#

just opened for curiosity package.lock

#
"node_modules/@nestjs/swagger": {
      "version": "11.0.3",
      "resolved": "https://registry.npmjs.org/@nestjs/swagger/-/swagger-11.0.3.tgz",
      "integrity": "sha512-oyrhrAzVJz1wYefIYDb6Y0f1VYb8BtYxEI7Ex0ApoUsfGZThyhW9elYANcfBXVaTmICrU8lCESF2ygF6s0ThIw==",
      "license": "MIT",
      "dependencies": {
        "@microsoft/tsdoc": "0.15.0",
        "@nestjs/mapped-types": "2.1.0",
        "js-yaml": "4.1.0",
        "lodash": "4.17.21",
        "path-to-regexp": "8.2.0",
        "swagger-ui-dist": "5.18.2"
      },
      "peerDependencies": {
        "@fastify/static": "^8.0.0",
        "@nestjs/common": "^11.0.1",
        "@nestjs/core": "^11.0.1",
        "class-transformer": "*",
        "class-validator": "*",
        "reflect-metadata": "^0.1.12 || ^0.2.0"
      },
      "peerDependenciesMeta": {
        "@fastify/static": {
          "optional": true
        },
        "class-transformer": {
          "optional": true
        },
        "class-validator": {
          "optional": true
        }
      }
    },

it mentions fastify/static why?

#

btw i set the exrpess adapter now i try to install the static assets module

#

still getting this error:

ERROR in ../../node_modules/@nestjs/serve-static/dist/loaders/fastify.loader.js 54:113-139\
Module not found: Error: Can't resolve '@fastify/static' in '/home/george/repos/has-george-read/node_modules/@nestjs/serve-static/dist/loaders'
#

these are my dependencies:

"dependencies": {
    "@golevelup/ts-jest": "^0.6.2",
    "@keyv/redis": "^4.2.0",
    "@mikro-orm/cli": "^6.4.4",
    "@mikro-orm/core": "^6.4.5",
    "@mikro-orm/migrations": "^6.4.5",
    "@mikro-orm/mysql": "^6.4.5",
    "@mikro-orm/nestjs": "^6.1.0",
    "@mikro-orm/reflection": "^6.4.5",
    "@mikro-orm/seeder": "^6.4.5",
    "@nestjs/cache-manager": "^3.0.0",
    "@nestjs/common": "^11.0.0",
    "@nestjs/config": "^4.0.0",
    "@nestjs/core": "^11.0.0",
    "@nestjs/platform-express": "^11.0.0",
    "@nestjs/serve-static": "^5.0.2",
    "@nestjs/swagger": "^11.0.3",
    "@sentry/node": "^8.50.0",
    "cache-manager": "^6.4.0",
    "class-transformer": "^0.5.1",
    "class-validator": "^0.14.1",
    "express": "^4.21.2",
    "helmet": "^8.0.0",
    "jest-extended": "^4.0.2",
    "nest-winston": "^1.10.1",
    "reflect-metadata": "^0.2.0",
    "request-ip": "^3.3.0",
    "swagger-ui-express": "^5.0.1",
    "uuid": "^11.0.5",
    "winston": "^3.17.0"
  },
  "devDependencies": {
    "@nestjs/cli": "^11.0.0",
    "@nestjs/schematics": "^11.0.0",
    "@nestjs/testing": "^11.0.0",
    "@relmify/jest-fp-ts": "^2.1.1",
    "@types/express": "^5.0.0",
    "@types/jest": "^29.5.2",
    "@types/node": "^20.3.1",
    "@types/request-ip": "^0.0.41",
    "@types/supertest": "^6.0.0",
    "jest": "^29.5.0",
    "supertest": "^7.0.0",
    "ts-jest": "^29.1.0",
    "ts-node": "^10.9.1",
    "tsconfig-paths": "^4.2.0"
  },