@foal/swagger
Version:
Swagger UI for FoalTS
159 lines (158 loc) • 6.59 kB
JavaScript
;
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SwaggerController = void 0;
// std
const fs_1 = require("fs");
const promises_1 = require("node:fs/promises");
const path_1 = require("path");
// 3p
const core_1 = require("@foal/core");
const swagger_ui_dist_1 = require("swagger-ui-dist");
function isUrlOption(option) {
return option.hasOwnProperty('url');
}
/**
* Serve Swagger UI to visualize and interact with API resources.
*
* @export
* @abstract
* @class SwaggerController
*/
class SwaggerController {
openApi;
/**
* Extend Swagger UI options.
*
* See https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/.
*
* @type {object}
* @example
* uiOptions = { docExpansion: 'none' };
* @memberof SwaggerController
*/
uiOptions = {};
/* Spec file(s) */
getOpenApiDefinition(ctx) {
if (isUrlOption(this.options)) {
return new core_1.HttpResponseNotFound();
}
if (!Array.isArray(this.options)) {
const document = this.openApi.getDocument(this.options.controllerClass);
return new core_1.HttpResponseOK(document);
}
const name = ctx.request.query.name;
if (typeof name !== 'string') {
return new core_1.HttpResponseBadRequest('Missing URL parameter "name".');
}
const option = this.options.find(option => option.name === name);
if (!option || isUrlOption(option)) {
return new core_1.HttpResponseNotFound();
}
return new core_1.HttpResponseOK(this.openApi.getDocument(option.controllerClass));
}
/* UI */
async index(ctx) {
if (!ctx.request.path.endsWith('/')) {
return new core_1.HttpResponseMovedPermanently(ctx.request.path + '/');
}
const page = await (0, promises_1.readFile)((0, path_1.join)(__dirname, 'index.html'), 'utf8');
return new core_1.HttpResponseOK(page)
.setHeader('Content-Type', 'text/html; charset=utf-8');
}
async main(ctx) {
const template = await (0, promises_1.readFile)((0, path_1.join)(__dirname, 'main.tpl.js'), 'utf8');
let body = '';
if (!Array.isArray(this.options)) {
const url = isUrlOption(this.options) ? this.options.url : 'openapi.json';
body = template
.replace('{{ urls }}', `url: "${url}"`)
.replace('{{ primaryName }}', '');
}
else {
let primaryName = '';
const options = this.options
.map(option => {
if (option.primary) {
primaryName = `\n \'urls.primaryName\': "${option.name}",`;
}
return {
name: option.name,
url: isUrlOption(option) ? option.url : `openapi.json?name=${option.name}`
};
});
body = template
.replace('{{ urls }}', `urls: ${JSON.stringify(options)}`)
.replace('{{ primaryName }}', primaryName);
}
body = body.replace('{{ uiOptions }}', JSON.stringify(this.uiOptions));
return new core_1.HttpResponseOK(body)
.setHeader('Content-Type', 'application/javascript');
}
swaggerUi() {
return this.createHttpResponseFile('swagger-ui.css', 'text/css');
}
swaggerUiBundle() {
return this.createHttpResponseFile('swagger-ui-bundle.js', 'application/javascript');
}
swaggerUiStandalonePreset() {
return this.createHttpResponseFile('swagger-ui-standalone-preset.js', 'application/javascript');
}
async createHttpResponseFile(filename, contentType) {
const filePath = (0, path_1.join)((0, swagger_ui_dist_1.getAbsoluteFSPath)(), filename);
const stream = (0, fs_1.createReadStream)(filePath);
const stats = await (0, promises_1.stat)(filePath);
return new core_1.HttpResponseOK(stream, { stream: true })
.setHeader('Content-Type', contentType)
.setHeader('Content-Length', stats.size.toString());
}
}
exports.SwaggerController = SwaggerController;
__decorate([
(0, core_1.Dependency)(core_1.OPENAPI_SERVICE_ID),
__metadata("design:type", core_1.OpenApi)
], SwaggerController.prototype, "openApi", void 0);
__decorate([
(0, core_1.Get)('/openapi.json'),
__metadata("design:type", Function),
__metadata("design:paramtypes", [core_1.Context]),
__metadata("design:returntype", void 0)
], SwaggerController.prototype, "getOpenApiDefinition", null);
__decorate([
(0, core_1.Get)('/'),
__metadata("design:type", Function),
__metadata("design:paramtypes", [core_1.Context]),
__metadata("design:returntype", Promise)
], SwaggerController.prototype, "index", null);
__decorate([
(0, core_1.Get)('/main.js'),
__metadata("design:type", Function),
__metadata("design:paramtypes", [core_1.Context]),
__metadata("design:returntype", Promise)
], SwaggerController.prototype, "main", null);
__decorate([
(0, core_1.Get)('/swagger-ui.css'),
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", void 0)
], SwaggerController.prototype, "swaggerUi", null);
__decorate([
(0, core_1.Get)('/swagger-ui-bundle.js'),
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", void 0)
], SwaggerController.prototype, "swaggerUiBundle", null);
__decorate([
(0, core_1.Get)('/swagger-ui-standalone-preset.js'),
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", void 0)
], SwaggerController.prototype, "swaggerUiStandalonePreset", null);