Skip to content

Commit

Permalink
feat(): routing platform independence (better static files serving so…
Browse files Browse the repository at this point in the history
…lution)
  • Loading branch information
flamewow committed Apr 11, 2022
1 parent b666b3e commit ed777f3
Show file tree
Hide file tree
Showing 5 changed files with 236 additions and 141 deletions.
34 changes: 24 additions & 10 deletions e2e/manual-e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,26 @@ import 'source-map-support/register';
import { NestFactory } from '@nestjs/core';
import { ApplicationModule } from './src/app.module';
import { DocumentBuilder, SwaggerModule } from '../lib';
import { FastifyAdapter } from '@nestjs/platform-fastify';
import {
FastifyAdapter,
NestFastifyApplication
} from '@nestjs/platform-fastify';
import { INestApplication } from '@nestjs/common';
import { ExpressAdapter } from '@nestjs/platform-express';

const port = 4001;
const host = '0.0.0.0';
const host = 'localhost';
const docRelPath = '/api-docs';

async function bootstrap() {
const app = await NestFactory.create<INestApplication>(
const app = await NestFactory.create<NestFastifyApplication>(
ApplicationModule,
new FastifyAdapter()
// new ExpressAdapter()
);

app.setGlobalPrefix('/api/v1');

const swaggerSettings = new DocumentBuilder()
.setTitle('Cats example')
.setDescription('The cats API description')
Expand Down Expand Up @@ -48,12 +53,21 @@ async function bootstrap() {
}
});

return app.listen(port, host);
}
SwaggerModule.setup('/swagger-docs', app, document, {
customSiteTitle: 'Demo API - Swagger UI',
swaggerOptions: {
persistAuthorization: true,
defaultModelsExpandDepth: -1
}
});

const baseUrl = `http://${host}:${port}`;
const startMessage = `Server started at ${baseUrl}; AsyncApi at ${
baseUrl + docRelPath
};`;
await app.listen(port, host);
const baseUrl = `http://${host}:${port}`;
const startMessage = `Server started at ${baseUrl}; SwaggerUI at ${
baseUrl + docRelPath
};`;

console.log(startMessage);
}

bootstrap().then(() => console.log(startMessage));
bootstrap();
77 changes: 32 additions & 45 deletions lib/swagger-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import { getGlobalPrefix } from './utils/get-global-prefix';
import { validatePath } from './utils/validate-path.util';
import * as jsyaml from 'js-yaml';
import swaggerUi from './swagger-ui';
import * as fs from 'fs';
import * as pathNode from 'path';
import { NestFastifyApplication } from '@nestjs/platform-fastify';
import { NestExpressApplication } from '@nestjs/platform-express';

export class SwaggerModule {
public static createDocument(
Expand Down Expand Up @@ -50,67 +50,54 @@ export class SwaggerModule {
: path
);

console.log(finalPath);
// httpAdapter.get('/test', (req, res) => {
// return 'test OK!';
// });

const yamlDocument = jsyaml.dump(document);
const jsonDocument = JSON.stringify(document);
const html = swaggerUi.generateHTML(finalPath, document, options);

const swaggerUIBasePath = swaggerUi.getSwaggerUiAbsoluteFSPath();
const swaggerUIAssetsNames = [
'swagger-ui.css',
'swagger-ui-bundle.js',
'swagger-ui-standalone-preset.js'
// 'favicon-32x32.png',
// 'favicon-16x16.png'
];

const ext2type = {
js: 'application/javascript',
css: 'text/css'
};
/*
* in oder to avoid using static serving libraries (they are routing platform dependant)
* swaggerUI assets are served manually
*/
swaggerUIAssetsNames.forEach((assetName) => {
const assetFullUrl = `${finalPath}/${assetName}`;
const [, assetExtension] = assetName.split('.');
const assetPath = pathNode.join(swaggerUIBasePath, assetName);

httpAdapter.get(assetFullUrl, async (req, res) => {
fs.readFile(assetPath, 'utf8', function (err, data) {
if (err) {
throw err;
}

res.type(ext2type[assetExtension]);
res.send(data);
});
});
});
const initJSFile = swaggerUi.getInitJs(document, options);

httpAdapter.get(`${finalPath}/swagger-ui-init.js`, (req, res) => {
res.type('js');
res.send(swaggerUi.getInitJs(document, options));
res.type('application/javascript');
res.send(initJSFile);
});

httpAdapter.get(finalPath, (req, res) => {
res.type('html');
res.type('text/html');
res.send(html);
});

httpAdapter.get(finalPath + '/', (req, res) => {
res.type('text/html');
res.send(html);
});

httpAdapter.get(`${finalPath}-json`, (req, res) => {
res.type('json');
res.type('text/json');
res.send(jsonDocument);
});

httpAdapter.get(`${finalPath}-yaml`, (req, res) => {
res.type('yaml');
res.type('text/yaml');
res.send(yamlDocument);
});

// serve JS, CSS, etc
const swaggerUIBasePath = swaggerUi.getSwaggerUiAbsoluteFSPath();
if (httpAdapter && httpAdapter.getType() === 'fastify') {
const fastifyApp = app as NestFastifyApplication; // TODO: figure out cleaner solution
fastifyApp.useStaticAssets({
root: swaggerUIBasePath,
prefix: `${finalPath}/`,
decorateReply: false
});
// fastifyApp.useStaticAssets({
// root: __dirname,
// prefix: `${finalPath}/test/`,
// decorateReply: false
// });
} else {
const expressApp = app as NestExpressApplication; // TODO: figure out cleaner solution
expressApp.useStaticAssets(swaggerUIBasePath, { prefix: finalPath });
}
}
}
44 changes: 14 additions & 30 deletions lib/swagger-ui.ts → lib/swagger-ui/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import * as swaggerUi from 'swagger-ui-dist';
const favIconHtml =
'<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />' +
'<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />';
let swaggerInit = '';

const htmlTplString = `
<!-- HTML for static distribution bundle build -->
Expand Down Expand Up @@ -190,42 +189,27 @@ const generateHTML = function (
customfavIcon = customfavIcon || false;
customSiteTitle = customSiteTitle || 'Swagger UI';
_htmlTplString = _htmlTplString || htmlTplString;
_jsTplString = _jsTplString || jsTplString;

const favIconString = customfavIcon
? '<link rel="icon" href="' + customfavIcon + '" />'
: favIconHtml;

const htmlWithCustomCss = _htmlTplString
const finalHtml = _htmlTplString
.toString()
.replace('<% customCss %>', customCss)
.replaceAll('<% baseUrl %>', baseUrl);

const htmlWithFavIcon = htmlWithCustomCss.replace(
'<% favIconString %>',
favIconString
);
const htmlWithCustomJs = htmlWithFavIcon.replace(
'<% customJs %>',
customJs ? `<script src="${customJs}"></script>` : ''
);
const htmlWithCustomCssUrl = htmlWithCustomJs.replace(
'<% customCssUrl %>',
customCssUrl ? `<link href="${customCssUrl}" rel="stylesheet">` : ''
);

const initOptions = {
swaggerDoc: swaggerDoc || undefined,
customOptions: options,
swaggerUrl: swaggerUrl || undefined,
swaggerUrls: swaggerUrls || undefined
};

swaggerInit = _jsTplString
.toString()
.replace('<% swaggerOptions %>', stringify(initOptions));

return htmlWithCustomCssUrl.replace('<% title %>', customSiteTitle);
.replace('<% favIconString %>', favIconString)
.replaceAll('<% baseUrl %>', baseUrl)
.replace(
'<% customJs %>',
customJs ? `<script src="${customJs}"></script>` : ''
)
.replace(
'<% customCssUrl %>',
customCssUrl ? `<link href="${customCssUrl}" rel="stylesheet">` : ''
)
.replace('<% title %>', customSiteTitle);

return finalHtml;
};

const generateInit = (swaggerDoc, opts) => {
Expand Down

0 comments on commit ed777f3

Please sign in to comment.