I am trying to create a function that would determine the dependents and dependencies of a given route's middleware in Express. The goal is to figure out how separated my routes are so that I can begin to think about the best place to begin a migration to a more microservice-based architecture.
Right now, I've figured out that I can access a list of middleware functions through Express' app._router.router._stack
object, from which I can dig into bound and routed dispatchers for a stack of middleware. Below is the output of a function I have written to that utilizes a bunch of classes to traverse the app
object to get a list of middleware functions.
The problem is that for anonymous functions (eg. those defined as methods on a controller), I cannot figure out a way to find the files these functions actually live in. That prevents me from easily accessing their dependencies and dependents, which I need for figuring out the function's scope and its relation to others.
expressMap.js output:
MIDDLEWARE:
Layer {
handle: [Function: router] {
params: {},
_params: [],
caseSensitive: undefined,
mergeParams: undefined,
strict: undefined,
stack: [ [Layer], [Layer] ]
},
name: 'router',
params: undefined,
path: undefined,
keys: [],
regexp: /^\/api\/?(?=\/|$)/i { fast_star: false, fast_slash: false },
route: undefined
}
MIDDLEWARE HANDLERS STACK:
/
/more-characters
FUNCTION DEFINTIONS IN ROUTE /:
(req, res, next) => {
console.log("inside getCharacters filecontroller")
fsCallback.readFile(path.resolve(__dirname, '../data/characters.json'),
'UTF-8',
(err, chars) => {
if (err) return next(createErr({
method: 'getCharacters',
type: 'reading file',
err,
}));
const parsedData = JSON.parse(chars);
res.locals.characters = parsedData.results;
return next();
});
}
(req, res, next) => {
res.status(200).set('Content-Type', 'text/plain').json({characters : res.locals.characters})
}
//// Note: skipping /more-characters route for space ////
I think I am basically asking for a way of creating some sort of control flow graph for Express (though ideally, one that is more agnostic would be great) that can link the routes I use to the functions they rely on in their specific context.
I initially approached this problem by making the expressMap.js function whose output is shown above, and while I could reliably list out all my middleware functions as objects and grab their definitions, I could not figure out how to get their filepaths.
I have been looking into creating some pseudo-CFG with a convoluted traversal of the Abstract Syntax Trees of my entire directory, but I can't frame the task well enough (or like, efficiently/elegantly enough) in my mind to get started. One of the main sticking points for me here is tracking calls between files (eg. going from app.use
in server.js, to some get method in /apiRouter.js
, to some randomController.middleware in randomController.js
.
The hacky solution I feel would be "search for an exact match of the text of the function definition in the directory, and then return the file it is found in," but I feel there has has to be a better way.
Any help is greatly appreciated!