UNPKG

yasui

Version:

Lightweight Express-based framework for REST and web APIs

137 lines 12.6 kB
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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