ExpressJS:Dynamické přidávání tras za běhu

Chci mít možnost přidávat nové trasy za běhu bez restartování serveru pomocí NodeJS &ExpressJS. Udělal jsem podobný přístup jako v tomto článku:https://alexanderzeitler.com/articles/expressjs-dynamic-runtime-routing/
Technicky jsem schopen přidávat nové soubory a logiku za běhu podobně v článku, ale problém je v tom, že když nebyla nalezena žádná trasa api, pošlu odpověď 404 JSON (jak má být).

Myslím, že problém, který mám, je ten, že moje dynamicky vytvářené trasy nejsou nikdy dosaženy, protože statické trasy mají přednost před dynamicky vytvářenými trasami. To znamená, že vytvořené trasy budou připojeny po zpracování chyb, a proto nebudou nikdy dosaženy. Můj kód v app.js

...

// Routes
app.use('/api/products', productRoutes);
app.use('/api/users', userRoutes);

...

/* This is where the dynamically created routes should be mounted */

// Error handling
app.use((req, res, next) => {
    const err = new Error('Not found');
    err.status = 404;
    next(err);
});

app.use((err, req, res, next) => {
    res.status(err.status || 500).json({error: {message: err.message}});
});

/* This is where the dynamic routes are mounted */

module.exports = app;

Když okomentuji zpracování chyb, jsem schopen dosáhnout tras, které jsem vytvořil během běhu, zatímco při zpracování chyb mohu dosáhnout pouze dynamicky vytvořených tras po restartu serveru, kterému se chci vyhnout.
Problém není vyřešen s parametry dotazu, protože dynamicky přidávané trasy se liší logikou, vlastnostmi modelu, http metodami/slovesy a koncovými body API. např.
GET/POST /api/{endpoint}
GET/POST /api/foo/{endpoint}
GET/PUT/DELETE /api/foo/bar/{endpoint}/:id

Myslím, že v zásadě potřebuji buď:
1) najít způsob, jak připojit dynamicky vytvořené trasy před zpracováním chyb – na kterém jsem momentálně zaseknutý nebo
2) upravit zásobník tras – o kterém jsem se dočetl, že je nepraktický, pomalý, má špatné praktiky a je náchylný k chybám
3) najít alternativní řešení

Doufám, že mi někdo pomůže.
Díky předem

UPRAVIT
Zde je kód pro vytváření nových tras. Relevantním koncovým bodem je /api/databases/ v metodě POST

const Database = require('../models/database');
const controller = require('./template/controller');
const creation = require('../Creation');

...

exports.createOne = (req, res, next) => {
  if (!creation.findFileInDirectory(`./backend/api/models/${req.body.name.singular}.js`) ||
      !creation.findFileInDirectory(`./backend/api/controllers/${req.body.name.singular}.js`) ||
      !creation.findFileInDirectory(`./backend/api/routes/${req.body.name.singular}.js`)) {
    controller.createOne(req, res, next, Database, {
      modelName: 'database',
    }, () => {
      //creation.createEndpoint(req.body.name, req.body.data, req.body.auth);
      creation.createEndpoint(req.body.name, req.body, req.body.auth);
    });
  } else {
    res.status(422).json({message: 'Endpoint exists already'});
  }
}

...

Řadič v úryvku je pouze modulární soubor řadiče, který zpracovává všechny mé operace CRUD všech koncových bodů různých modelů. Každá trasa je rozdělena na modely, ovladače a trasy, aby byla oddělena a lépe zachována jejich logika.

V metodě POST nejprve zkontroluji, zda již existuje koncový bod, který se má vytvořit. Pokud ano, odpovím 422, že koncový bod již existuje. Pokud neexistuje, vytvořím záznam s mým modulárním řadičem v koncovém bodu databází a vytvořím model, řadič a trasu pro koncový bod, který by měl být vytvořen.

Logika vytváření je následující:

const createEndpoint = (name, data, auth) => {
    createFile(`./backend/api/models/${name.singular}.js`, model.createModel(capitalize(name.singular), data), () => {
      createFile(`./backend/api/controllers/${name.singular}.js`, controller.createController({singular: capitalize(name.singular), plural: name.plural}, data.data), () => {
        createFile(`./backend/api/routes/${name.singular}.js`, route.createRoute({singular: capitalize(name.singular), plural: name.plural}, auth), () => {
          const app = require('../../app');
          mountEndpoints(name.singular, app);
        });
      });
    });
};

Zde v podstatě předávám data z metody POST do souboru modelu, řadiče a trasy, které jsou vytvořeny asynchronně. Když jsou všechny soubory vytvořeny, připojím trasu koncového bodu do aplikace. Logika pro připojení trasy je:

const mountEndpoints = (path, app) => {
  const module = require(`../routes/${path}`);
  app.use(`/api/${module.plural ? `${module.plural}` : `${path}s`}`, module);
}

Vytvořená trasa může vypadat takto:

const express   = require('express');
const router    = express.Router();
const checkAuth = require('../middleware/check-auth');

const ProductController = require('../controllers/product');

router.route('/')
    .get(ProductController.getAll)
    .post(checkAuth, ProductController.createOne);

router.route('/:id')
    .get(ProductController.getOne)
    .patch(checkAuth, ProductController.patchOne)
    .delete(checkAuth, ProductController.deleteOne);

module.exports = router;
module.exports.plural = 'products';

checkAuth obsahuje určitou logiku pro autorizaci/ověření.

Kód dělá v podstatě to, co chci, aby dělal, kromě toho, že nevím, jak zacházet s umístěním trasy před zpracováním chyb.

Odpověď

Expresní trasy budou zpracovány v pořadí vytvoření.

Chcete-li přidat trasy v konkrétních místech za app Definici můžete vytvořit zástupný směrovač a připojit k němu cesty místo app sám.

Express nepodporuje mazání tras, jakmile jsou definovány, ale můžete nahradit celý router.

Vytvořte expresní instanci routeru (nebo dokonce jinou app v případě potřeby) k připojení dynamických koncových bodů. Předefinujte směrovač, kdykoli chcete změnit směrování (kromě přidání na konec zásobníku směrovačů, který podporuje expresní).

// Routes
app.use('/api/products', productRoutes);
app.use('/api/users', userRoutes);

let dynamicApiRouter = null

export function setupDynamicRouter(config) {
  dynamicApiRouter = new express.Router()
  // Add routes to dynamicApiRouter from `config`
  dynamicApiRouter[config.method](config.path, config.handler)
}

app.use('/api', (req, res, next) => dynamicApiRouter(req, res, next))

// Error handling
app.use((req, res, next) => {
    const err = new Error('Not found');
    err.status = 404;
    next(err);
});

app.use((err, req, res, next) => {
    res.status(err.status || 500).json({error: {message: err.message}});
});

Poté, když připojíte nový koncový bod, vložte směrovač a odstraňte /api prefix cesty, jak je nyní zpracováno mimo router v nadřazeném app .

const mountEndpoints = (path, router) => {
  const module = require(`../routes/${path}`);
  router.use(`/${module.plural ? `${module.plural}` : `${path}s`}`, module);
}