I have set a route in Express looking like this:
app.get('/api/:type/:id', api.getItemById);
The function api.getItemById is inside api module in routes. But inside api module I have to run a function that connects to database, and then defines all responder functions like this:
couchbase.connect(dbConfiguration, function (err, bucket) {
if (err) {
throw (err)
}
exports.getItemById = function (req, res) {
if (req.params.type == 'tag' || req.params.type == 'user' || req.params.type == 'asset' || req.params.type == 'expense' || req.params.type == 'income') {
get(req, res, req.params.type);
} else {
res.send(400);
}
};
});
The problem is that in this case the application doesn't find getItemById function and throws this:
.get() requires callback functions but got a [object Undefined]
I am not sure I do it properly. Could you please advise how I can make that function visible to the node app if defined inside a callback function?
In short: you can't. require is synchronous and expects that [module.]exports is set synchronously (at the moment the module is loaded).
You could use a module-scoped variable which is initially false, and is set to true once
your database is set up. Your route handler could check for that:
var ready = false;
// connect to database
couchbase.connect(dbConfiguration, function (err, bucket) {
if (err) {
throw (err)
}
ready = true;
};
// export your route handler
exports.getItemById = function (req, res) {
// check for readiness
if (! ready)
return res.send(500); // 'Internal Server Error', or any error you like
// if ready, perform the regular action
if (req.params.type == 'tag' || req.params.type == 'user' || req.params.type == 'asset' || req.params.type == 'expense' || req.params.type == 'income') {
get(req, res, req.params.type);
} else {
res.send(400);
}
};
If you don't want a setup like this (where requests can get handled before the database is connected to), you need to postpone the startup of your server (app.listen(...) or equivalent) until all asynchronous startup actions are done. That would require a bit more effort though.
You cannot not export getItemById; you should export an initialization function that passes the function in a callback whenever the database is set up:
exports.init = function(callback) {
couchbase.connect(dbConfiguration, function (err, bucket) {
if (err) {
throw (err)
}
var getItemById = function (req, res) {
if (req.params.type == 'tag' || req.params.type == 'user' || req.params.type == 'asset' || req.params.type == 'expense' || req.params.type == 'income') {
get(req, res, req.params.type);
} else {
res.send(400);
}
};
callback(getItemById);
});
}
And then perform your require like so:
require("api").init(function(getItemById) {
// set up express...
app.get('/api/:type/:id', getItemById);
// ...
});