yasui
Version:
Lightweight Express-based framework for REST and web APIs
137 lines • 12.6 kB
JavaScript
import kleur from 'kleur';
import bodyParser from 'body-parser';
import { createRequire } from 'module';
import express from 'express';
import { Injector } from './injector.js';
import { LoggerService } from './services/index.js';
import { AppService } from './utils/app.service.js';
import { DecoratorValidator } from './utils/decorator-validator.js';
import { SwaggerService } from './utils/swagger.service.js';
export class Core {
config;
logger;
swagger;
decoratorValidator;
appService;
injector;
app;
constructor(conf) {
this.config = conf;
if (conf.enableDecoratorValidation === undefined) {
this.config.enableDecoratorValidation = true;
}
this.logger = new LoggerService();
this.appService = new AppService(this.config);
this.decoratorValidator = this.config.enableDecoratorValidation
? new DecoratorValidator(this.config)
: null;
this.injector = new Injector(this.logger, this.decoratorValidator, conf.debug);
this.swagger = new SwaggerService(this.decoratorValidator);
this.app = express();
}
createApp() {
this.logger.start();
this.app.use(bodyParser.json());
if (this.config.apiKey) {
this.app.use(this.appService.auth.bind(this.appService));
}
if (this.config.debug) {
this.logger.warn('debug mode is enabled');
this.app.use(this.appService.logRequest.bind(this.appService));
}
this.app.use((req, res, next) => {
req.logger = new LoggerService().start();
next();
});
for (const injection of this.config.injections || []) {
this.injector.register(injection.token, injection.provide);
}
this.loadMiddlewares();
this.logger.log('load routes from controllers...');
this.loadControllers();
this.setupSwagger();
this.app.get('/', (req, res) => { res.sendStatus(200); });
this.app.use(this.appService.handleNotFound.bind(this.appService));
this.app.use(this.appService.handleErrors.bind(this.appService));
return this.app;
}
build(Provided) {
return this.injector.build(Provided);
}
useMiddleware(Middleware) {
if (this.isClassMiddleware(Middleware)) {
const middleware = this.build(Middleware);
return middleware.run(middleware);
}
return Middleware;
}
loadMiddlewares() {
for (const Middleware of this.config.middlewares || []) {
try {
this.app.use(this.useMiddleware(Middleware));
}
catch (err) {
this.logger.error(`failed to load ${Middleware.name || '<invalid function>'} middleware\n${err}`);
}
}
}
loadControllers() {
for (const Controller of this.config.controllers || []) {
try {
this.decoratorValidator?.validateController(Controller);
const controller = this.build(Controller);
const path = controller.path;
const router = controller.configureRoutes(controller, this);
this.app.use(path, router);
if (this.config.swagger?.generate) {
this.swagger.registerControllerRoutes(Controller, path);
}
this.logger.success(`${kleur.italic(`${path}`)} routes loaded`);
}
catch (err) {
this.logger.error(`failed to load ${Controller.name || '<invalid controller>'} routes\n${err}`);
}
}
}
setupSwagger() {
if (!this.config.swagger?.generate) {
return;
}
try {
const require = createRequire(import.meta.url);
const swaggerUi = require('swagger-ui-express');
let swaggerPath = this.config.swagger.path || '/api-docs';
if (!swaggerPath.startsWith('/')) {
swaggerPath = '/' + swaggerPath;
}
const swaggerConfig = this.swagger.getSwaggerConfig(this.config.swagger, !!this.config.apiKey);
const swaggerJsonPath = `${swaggerPath}/swagger.json`;
this.app.get(swaggerJsonPath, (req, res) => {
res.json(swaggerConfig);
});
this.app.use(swaggerPath, swaggerUi.serve, swaggerUi.setup(swaggerConfig, {
swaggerOptions: {
defaultModelsExpandDepth: 0,
url: swaggerJsonPath,
},
}));
this.logger.success(`${kleur.italic(`${swaggerPath}`)} swagger documentation loaded`);
}
catch (err) {
this.logger.warn('swagger-ui-express not found.\n' +
'Install it to enable swagger documentation: npm install swagger-ui-express.');
if (this.config.debug) {
this.logger.error(`swagger setup error: ${err}`);
}
}
}
isClassMiddleware(Md) {
if (typeof Md !== 'function') {
return false;
}
return Md.prototype &&
typeof Md.prototype.run === 'function' &&
Md.prototype.constructor === Md;
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29yZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9jb3JlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxNQUFNLE9BQU8sQ0FBQztBQUMxQixPQUFPLFVBQVUsTUFBTSxhQUFhLENBQUM7QUFDckMsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLFFBQVEsQ0FBQztBQUN2QyxPQUFPLE9BS04sTUFBTSxTQUFTLENBQUM7QUFHakIsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUN6QyxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDcEQsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ3BELE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBQ3BFLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQWlCNUQsTUFBTSxPQUFPLElBQUk7SUFDUixNQUFNLENBQWM7SUFDcEIsTUFBTSxDQUFnQjtJQUN0QixPQUFPLENBQWlCO0lBQ3hCLGtCQUFrQixDQUE0QjtJQUU3QyxVQUFVLENBQWE7SUFDdkIsUUFBUSxDQUFXO0lBQ25CLEdBQUcsQ0FBYztJQUV6QixZQUFZLElBQWlCO1FBQzNCLElBQUksQ0FBQyxNQUFNLEdBQUcsSUFBSSxDQUFDO1FBQ25CLElBQUksSUFBSSxDQUFDLHlCQUF5QixLQUFLLFNBQVMsRUFBRSxDQUFDO1lBQ2pELElBQUksQ0FBQyxNQUFNLENBQUMseUJBQXlCLEdBQUcsSUFBSSxDQUFDO1FBQy9DLENBQUM7UUFDRCxJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksYUFBYSxFQUFFLENBQUM7UUFDbEMsSUFBSSxDQUFDLFVBQVUsR0FBRyxJQUFJLFVBQVUsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDOUMsSUFBSSxDQUFDLGtCQUFrQixHQUFHLElBQUksQ0FBQyxNQUFNLENB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