First-class functions
July 13, 2018
When I first started my nodejs webapp project, I wrote all my routes in a single app.js file:
app.get('/some route', (req,res) => {
/*do something in the callback function*/
});
app.get('/some other route', (req,res) => {
/*do something in the callback function*/
});
app.post('/some other route', (req,res) => {
/*do something in the callback function*/
});
//and so on...
Soon I realized that since the codes in every routes are pretty long, the app.js file itself became too long. It takes some time to locate the route I want and it’s also difficult to maintain. So naturally what came into my mind is something I believe that every programmer has learned: modular design. I then tried to divide the routes into modules according to their funtionality: user controll, appointment controll, etc.
Before we dig into how I implemented the modules, let’s talk about the title of this post: first class functions. According to wikipedia: “a programming language is said to have first-class functions when it supports passing functions as arguments to other functions, returning them as the values from other functions, and assigning them to variables or storing them in data structures”. This was kind of a new concept to me when I ran into it, as it’s not a common feature in the languages that I’m most familiar with, i.e.Java and C.
But then I realized I’ve been using it in every routes I wrote in Nodejs. In the above code, the anonymous callback function is a first-class function since it’s passed into a get or post function as an argument. With this in mind, I implemented the modules as follows:
//app.js
//db is the database connection object defined earlier in the code
app.post('/adduser', userController.addUser(db));
app.post('/login', userController.login(db));
app.get('user/:id', userController.getUserpage(db));
//userController.js
module.exports = {
addUser: (database) => {
return (req, res) => {
//do some query using the database object, and return the result to client in a response
}
}
login: (database) => {
return (req, res) => {
//do some other query
}
}
getUserpage: (database) => {
return (req, res) => {
//do some other query
}
}
}
The main idea is that, since the get or post function in the Expressjs framework expect a callback function with signature(req,res,next), we can’t directly pass the database object into the callback. Instead, various helper functions are defined which takes the database object as an argument. They will return the callback funtion as a value, which has the expected signature and will do something with the database object and send a response back to the client. The helper functions are then exported in a module and passed into the corresponding routes. This design utilizes the first-class function feature of JavaScript to split the routes into different modules. A single database object can be shared by all the routes, so there’s no need to create a separate database object in every module.
But of course, I’m not proficient in Javascript or Nodejs, so it’s likely that the above is not the best approach and there are far better ways to do it. If you have any suggestion or want to discuss, feel free to comment to let me know!
Btw, there are actually first-class functions in C, and they are called function pointers!