How to create my own module of functions in a node.js app
I'm building my node.js app which has the following structure:
- server.js
- controllers/user.js
server.js require the user.js controller with:
require('./controllers/user.js').route(app, mongoose);
the controller/user.开发者_运维知识库js file is like:
function route(app, mongoose){
function route(app, mongoose){
// Create new User item
app.post('/user/create', function(req, res){
...
}
// Edit user
app.put('/user/:id/edit', function(req, res){
...
}
...
}
module.exports.route = route;
This is working fine. I know want to had middleware in the Edit user function for instance so it looks like:
...
app.put('/user/:id/edit', loadUser, function(req, res){
...
If I define loadUser function right above this line it's working fine. When I add all the middleware fonction in a file './lib/middleware.js' and when I try to load that file in user.js with:
require('../lib/middleware.js').create(); // Create is the exported function
this does not work and I have the error message saying that loadUser is an unknow function.
Any idea ?
** UPDATE **
I have updated the files such that, in server.js (main file) I have:
...
var middleware = require('./lib/middleware.js');
...
require('./controllers/user.js').route(app, mongoose, middleware);
...
In middleware.js, I then have:
function create() {
function loadUser(req, res, next) {
// You would fetch your user from the db
var user = users[req.params.id];
if (user) {
req.user = user;
next();
} else {
next(new Error('Failed to load user ' + req.params.id));
}
}
return module;
}
In controllers/user.js I have
function route(app, mongoose, middleware){
...
// Modify an user
app.put('/user/edit', middleware.loadUser, function(req, res){
...
}
...
}
When I run the app (node server.js) I then have the following error:
Error: PUT route /user/edit requires a callback
I am not sure to return the correct thing within middleware.js, not really familiar with module stuff yet. I also tried the "module.exports.create = create;" but same thing.
UPDATE WITH ANOTHER TRY
what if I create a module for the function ? In ./lib/middleware.js I would have:
(function(){
var middleware = {};
middleware.loadUser = function () {
console.log("loadUser");
}
return middleware;
}());
And in server, I call it:
var middleware = require('./lib/middleware.js');
middleware.loadUser;
It seems to me that should work but it does not...
"global" scope in a file is actually module scope. Just by creating a function in a different file it does become in scope in your original file.
What you want to do instead is
// routes.js
var middleware = require("../lib/middleware.js").create();
app.put('/user/:id/edit', middelware["loadUser"], function(req, res){
You will find that global variables actually write to module
in their scope.
Then your function loadUser() { ... }
should exist in the module
property.
// middleware.js
function create() {
...
return module;
}
If you return module
from your create function your returning global scope.
[Edit]
function create() {
function loadUser(req, res, next) {
// You would fetch your user from the db
var user = users[req.params.id];
if (user) {
req.user = user;
next();
} else {
next(new Error('Failed to load user ' + req.params.id));
}
}
return module;
}
You either need to add module.loadUser = loadUser
or define loadUser
in module scope. I.e. outside the create
function.
[Further Edit]:
A standard setup would be something like:
// middleware.js
(function() {
function loadUser(...) {
...
}
...
module.exports.loadUser = loadUser;
})();
//otherfile.js
var middle = require("middleware");
middle.loadUser();
When code is loaded using require() it doesn't put anything into the global context. You have to bind it to a variable.
For example when you require your middleware file, you are able to call create() only because the module.exports object is returned from the require() function and you are able to access the call site directly. Here is how you would keep a reference to the require()d code so you could access it later:
var middleware = require('../lib/middleware.js');
middleware.create();
and probably this is what you want:
app.put('/user/:id/edit', middleware.loadUser, function(req, res) ...
update: As raynos pointed out, no function wrapper is advised in this case. See his comment.
Note that I wrapped the loadUser function reference in an anonymous function. Leaving the code as you had it would have worked as long as your code didn't rely on the value of 'this' internally.
update: I think I misunderstood what you were trying to do with create(). The above works if you define your loadUser() function as directly part of the module. If you need to do something else tricky in your Create() function you can use what I wrote above by doing something like
var loadUser = middleware.create();
Then you'll have the loadUser function defined in scope.
精彩评论