import express from 'express';
import swaggerUiDist from 'swagger-ui-dist';
import { getOpenApiSpec } from '../openapiSpec.js';
const swaggerDistPath = swaggerUiDist.getAbsoluteFSPath();
// #region Helpers
function renderDocsHtml() {
return `
Dash API
`;
}
// #endregion
/**
* Registers documentation and interactive API tester under /docs/.
* @param {import('express').Application} app - Express app
* @param {string} [basePath=''] - Base path (e.g. '/api')
*/
export function register(app, basePath = '') {
const docsRouter = express.Router();
// #region USE /docs (redirect)
// Redirect /docs (or /api/docs) to /docs/ so relative assets resolve properly
docsRouter.use((req, res, next) => {
const rawPath = req.originalUrl.split('?')[0];
if (rawPath === '/docs' || rawPath === '/api/docs' || rawPath === '/api/docs/') {
const query = req.originalUrl.includes('?') ? '?' + req.originalUrl.split('?')[1] : '';
return res.redirect(301, '/docs/' + query);
}
next();
});
// #endregion
// #region GET /openapi.json
// Serve OpenAPI 3.0 specification JSON
docsRouter.get('/openapi.json', (_req, res) => {
try {
const spec = getOpenApiSpec();
res.setHeader('Content-Type', 'application/json; charset=utf-8');
res.send(JSON.stringify(spec, null, 2));
} catch (err) {
console.error('Failed to generate OpenAPI spec:', err);
res.status(500).json({ error: 'Failed to generate OpenAPI specification' });
}
});
// #endregion
// #region GET /
// Serve HTML UI for /docs/ and /docs/index.html
docsRouter.get('/', (_req, res) => {
res.setHeader('Content-Type', 'text/html; charset=utf-8');
res.send(renderDocsHtml());
});
// #endregion
// #region GET /index.html
docsRouter.get('/index.html', (_req, res) => {
res.setHeader('Content-Type', 'text/html; charset=utf-8');
res.send(renderDocsHtml());
});
// #endregion
// #region USE /docs (static assets)
// Serve static assets from swagger-ui-dist (CSS, JS bundles, icons)
docsRouter.use(express.static(swaggerDistPath, { index: false }));
// #endregion
// #region USE /docs
// Mount on /docs
app.use('/docs', docsRouter);
// #endregion
// #region USE /docs
// Also mount on /api/docs and alias /api/openapi.json if basePath is set
if (basePath) {
app.use(basePath + '/docs', docsRouter);
app.get(basePath + '/openapi.json', (_req, res) => res.redirect(301, '/docs/openapi.json'));
}
// #endregion
}