import { Express } from 'express-serve-static-core'; import cors from 'cors'; import morganMiddleware from '../logging/MorganMiddleware.js'; import { AddressInfo } from 'net'; import http from 'http'; import helmet from 'helmet'; import express from 'express'; import WorkerTask from '../process/WorkerTask.js'; import multer from 'multer'; import SessionMiddleware from '../middlewares/SessionMiddleware.js'; import Config from '../config/Config.js'; import logger from '../shared/logging/WinstonLogger.js'; import ParamsCallbackManager from '../middlewares/ParamsCallbackManager.js'; import ApiRoutesManager from '../routes/ApiRoutesManager.js'; import compression from 'compression'; import ClientVersionCheckerMiddleware from '../middlewares/ClientVersionCheckerMiddleware.js'; import swaggerUi from 'swagger-ui-express'; import path from 'path'; import DojoCliVersionHelper from '../helpers/DojoCliVersionHelper.js'; class API implements WorkerTask { private readonly backend: Express; private server!: http.Server; constructor() { this.backend = express(); this.initOpenAPI(); this.initBaseMiddlewares(); this.backend.use(ClientVersionCheckerMiddleware.register()); ParamsCallbackManager.registerOnBackend(this.backend); SessionMiddleware.registerOnBackend(this.backend); ApiRoutesManager.registerOnBackend(this.backend); } private initBaseMiddlewares() { this.backend.use(multer({ limits: { fieldSize: 100 * 1024 * 1024 } }).none()); //Used for extract params from body with format "form-data", The none is for say that we do not wait a file in params this.backend.use(morganMiddleware); //Log API accesses this.backend.use(helmet()); //Help to secure express, https://helmetjs.github.io/ this.backend.use(cors()); //Allow CORS requests this.backend.use(compression()); //Compress responses this.backend.use((_req, res, next) => { DojoCliVersionHelper.getLatestVersion().then(latestVersion => { res.header('dojocli-latest-version', latestVersion); next(); }); }); } private initOpenAPI() { const options = { customSiteTitle: 'Dojo API', explorer : false, swaggerOptions : { url: '../OpenAPI.yaml' } }; this.backend.get('/docs/OpenAPI.yaml', (_req, res) => res.sendFile(path.resolve(__dirname + '/../../assets/OpenAPI/OpenAPI.yaml'))); this.backend.use('/docs/swagger', swaggerUi.serveFiles(undefined, options), swaggerUi.setup(undefined, options)); this.backend.get('/docs/redoc.html', (_req, res) => res.sendFile(path.resolve(__dirname + '/../../assets/OpenAPI/redoc.html'))); this.backend.get('/docs/', (req, res) => { const prefix = req.url.slice(-1) === '/' ? '' : 'docs/'; res.send(` <!DOCTYPE html> <html lang="en"> <body> <ul> <li><a href="${ prefix }OpenAPI.yaml">OpenAPI</a></li> <li>GUI <ul> <li><a href="${ prefix }swagger/">Swagger</a></li> <li><a href="${ prefix }redoc.html">Redoc</a></li> </ul> </li> </ul> </body> </html> `); }); } run() { this.server = this.backend.listen(Config.api.port, '0.0.0.0', () => { const { port, address } = this.server.address() as AddressInfo; logger.info(`Server started on http://${ address }:${ port }`); }); } } export default API;