Home Manual Reference Source

src/App.js

import { join as pathJoin } from 'path';
import { readdirSync } from 'fs';
import Koa from 'koa';
import locale from 'koa-locale';

import Route from './routes/Route';
import notFound from './middlewares/notFound';

import { objValToArray } from './utils/utils';
import * as docGenerator from './utils/docGenerator';

export default class App {
  /**
   * @ignore
   */
  routeParam = null;
  /**
   * @ignore
   */
  routes = {};

  constructor(opt) {
    const {
      routeParam = {},
      port = process.env.PORT || 3000,
      docPath = pathJoin(__dirname, '..', 'apidoc'),
      generateDoc = false,
    } = opt;
    this.routeParam = routeParam;
    /**
     * @ignore
     * @type {number}
     */
    this.port = port;
    /**
     * @ignore
     * @type {Koa}
     */
    this.app = new Koa();

    locale(this.app);

    docGenerator.init(docPath, generateDoc);
  }

  /**
   * @ignore
   */
  _getAllRoutes(path, prefix) {
    this.routes[prefix] = this.routes[prefix] || {};

    readdirSync(path)
      .filter(file => file.endsWith('.js') || file.endsWith('.ts'))
      .forEach(file => {
        const RouteClass = require(pathJoin(path, file)).default;
        if (RouteClass && RouteClass.prototype instanceof Route) {
          const route = new RouteClass({
            prefix,
            app: this.app,
            routes: this.routes[prefix],
            ...this.routeParam,
          });
          this.routes[prefix][route.constructor.name] = route;
        }
      });
    return objValToArray(this.routes[prefix]);
  }

  /**
   * @access public
   * @desc adds the provided functions to the list of Koa middlewares to be executed for all routes.
   * @param {function} middlewares an array of Koa-compliant middlewares
   * @return { }
   */
  addMiddlewares(middlewares) {
    middlewares.forEach(e => this.addMiddleware(e));
  }

  /**
   * @access public
   * @desc adds the provided function to the list of Koa middlewares to be executed for all routes.
   * @param {function[]} middleware an array of middlewares
   * @return { }
   */
  addMiddleware(middleware) {
    this.app.use(middleware);
  }

  /**
   * @access public
   * @desc "mounts" a folder, scanning it for route files, then adding the discovered routes to the app.
   *       a route is a class which extends {@link Route}
   * @param {string} pathFolder the path of the folder to mount
   * @param {string} [prefix='/'] an optional prefix to prepend to all of the folder's routes
   * @return { }
   */
  mountFolder(pathFolder, prefix = '/', opt = {}) {
    const { generateDoc = true } = opt;
    const routes = this._getAllRoutes(pathFolder, prefix);
    for (const route of routes) {
      route.generateDoc = generateDoc;
      route.mount();
      this.app.use(route.koaRouter.middleware());
    }
  }

  /**
   * @access public
   * @desc Launches the app and starts listening on the configured port.
   * @return {Koa}
   */
  async start() {
    this.app.use(notFound());

    docGenerator.end();

    return this.app.listen(this.port);
  }
}