I am writing a Node.JS REST API using Express, and I was a little confused about the require() and exports statements in Node.JS.
For instance, let's say I am writing a simple app wherein app.js contains the basic app.get statements, routes.js contains the functions passed as a callback to those app.get statements and events.js contains the Mongoose Schemas and Models.
Now, if routes.js requires events.js, can I call Model.find() and functions like those in routes.js and if yes, what exports will I have to make from events.js?
No need to export anything from model. Just require it.
In routes.js, you can access your model using mongoose.model('Schema')
routes.js
require('./events.js')
var mongoose = require('mongoose')
, Model = mongoose.model('myModel')
Related
I'm in the process of learning NodeJS (using Express), and came across something that struck me as odd.
In app.js i'm requiring a module (passport in this case), and then requiring a second module (passport-strats.js) which I developed. Inside of passports-strats I have to re-require passport even though it's already required in app.js.
This isn't the only example, I have some modules required in three files that are all tightly related. Is this standard or am I missing some crucial piece of structuring NodeJS applications?
For you require the passport module once you should require it in passport-strats.js and export it from this module. In app.js you can use both modules just importing passport-strats.js. ie:
//passport-strats.js
var {passport} = require("./path");
//other code
module.exports = { passport, someVariableFromCurrentModel };
//In app.js
var {passport, someVariableFromCurrentModel} = require("./passport-strats");
I'm working through this Node ToDoList App API tutorial. It has one model, one controller and one routes file:
https://www.codementor.io/olatundegaruba/nodejs-restful-apis-in-10-minutes-q0sgsfhbd
Repo:
https://github.com/generalgmt/RESTfulAPITutorial
In the model, we use mongoose to define TaskSchema and export mongoose.model('Tasks', TaskSchema);
In the controller, we create a Task var, set equal to mongoose.model('Tasks', TaskSchema); and use it to define several controller methods.
The server.js requires Task from the model, but never seems to use it for anything. The server also requires the routes file, which in turn require the controller, but I can'a see how they ever interact with the model.
How does the rest of the app know about the model? How does the controller know the schema for Task? Is this all mongoose magic?
The Task schema is being called in the controller in line #4 https://github.com/generalgmt/RESTfulAPITutorial/blob/master/api/controllers/todoListController.js#L4
It does seem like the model being required in server.js is not used.
Server.js or routes don't need to interact with the schema, as all the methods required to interact with the schema are required in the Task constructor. The controller knows about the Task schema because it is being required in the controller.
I am trying to organize my project according to Express 4.x new express.Router() method.
As Express' documentation describes it,
A router object is an isolated instance of middleware and routes. You
can think of it as a “mini-application,” capable only of performing
middleware and routing functions.
For the sake of better understanding, let's consider this project structure:
project/
index.js
routes/
myRouter.js
...
...
And the files themselves:
index.js
const express = require('express');
const app = express();
const path = require('path');
const myModule = require('myModule');
app.use('/myRouter', require('routes/myRouter'));
// some more code using myModule set of functions
routes/myRouter.js
const express = require('express');
const path = require('path');
const router = express.Router();
const myModule = require('myModule');
router.get('/', function(req, res){
// some more code using myModule set of functions
});
module.exports = router;
As you can see, both files need to use myModule's functions, so AFAIK both files need to require myModule.
How does Express handle this situation?
As I see it, Express directly imports myRouter's code into index.js via module.exports. If so, is the engine somehow pre-compiling it? And then aren't myRouters' requires redundant?
If not, how does it affect performance? Should I avoid routers for my kind of task?
First thing would be that it is not being compiled, it's not es6. Second app.js imports the module and run that module for your route so imports in your myRouter.js is completely necessary. This article would certainly help you understand modules. One more thing is that it does decrease your application performance. Express is used on node.js and node.js imports are optimised with V8 engine. So don't worry about performance.
How does Express handle this situation?
Express doesn't, Node does. From the docs
Modules are cached after the first time they are loaded. This means (among other things) that every call to require('foo') will get exactly the same object returned, if it would resolve to the same file.
Multiple calls to require('foo') may not cause the module code to be executed multiple times. This is an important feature....
So taking your application into consideration, myModule is already cached by the time the router loads it as app.js would be required first; any performance impact would be negligible.
I've picked up a project from another developer, uses the typical MEAN stack with the entry point being server.js.
Now, in server.js, the module that does:
var express = require('express');
var app = express();
var passport = require('passport');
There are another 2 lines of code that look like they are doing some sort of routing but I can't figure out what it actually means:
require('./routes.js')(app, passport);
require('./apiRequest/authenticate')(app, passport);
I'm confused because it looks like require() is called from the global scope, whereas all the other routing methods are called off app, i.e app.use(). Can someone explain what the sets of parameters mean, and why are there two sets also where is require() called from, is it provided by Express?
routes.js and apiRequest/authenticate are two local (project) modules / js files that are basically required here.
express and passport are node modules/libraries that are provided from npm_modules, via node module resolution.
app is simply an express instance created by invoking the express module/default function.
The parameters passed to the required local modules (routes and authenticate) are just parameters passed to those modules (default exported function) that can be used further in those files (e.g. if you look in routes.js you will probably see that they use app.use(..., where app is given as param as well as the passport module)
To explain the syntax require('./routes.js')(app, passport); more clearly:
require - node OOB function for importing modules into the current file/module
require('./routes.js') resolves the default export from the routes.js file which in this case is a function
...(app, passport) this function (from above point) is then invoked with the provided params (which were previously defined here - i.e. imported with require)
I set up a web server using node JS and the Express module. My code is as follows :
file tree:
/src
|
+-- server.js
+-- /app
|
+-- routes.js
server.js
// set up ======================================================================
var express = require('express');
var app = express();
var mongoose = require('mongoose');
...
// configuration ===============================================================
mongoose.connect(configDB.url);
...
// routes ======================================================================
require('./app/routes.js')(app, passport);
// launch ======================================================================
app.listen(port);
routes.js
module.exports = function(app, passport) {
app.get('/some-route', function(req, res) {
// this line bugs out
var User = mongoose.model('User', userSchema);
});
};
My question:
Calling mongoose.model() in routes.js throws the following error
ReferenceError:mongoose is not defined
Why is mongoose not known in this context when I've included it in server.js, the file in which routes.js is being included? Should I require() mongoose again in routes.js? What am I missing here?
Variables defined within a module are local only to that module. They are not in the scope of other modules that you require() in with that module. That's why mongoose is not know to your routes module. The require() operation does not insert the code right into the calling module. Instead, it loads that code from disk and then inserts it into its own function and calls that function. This gives each loaded module its own independent scope. It is not inserted into the current scope.
In cases like this, you have several choices:
Require() in the mongoose module again in routes. This is generally preferred when possible because this makes the routes module more self sufficient and easier to reuse as it requires in the things it needs.
Pass in the object you want to share with the routes constructor just like you are passing in app and passport. This method is preferred when the item needed by the other module is not just the result of a simple module load. For example, app is the result of calling a constructor function so the only way for another module to use the same app instance is for you to pass it.
You can have routes call out to some other module to request information. For example, since you've already passed the app object to routes, you could put the mongoose object as either a property on the app object so it could be referenced that way or you could add a method to the app object to retrieve it via the method call.
In this case, since mongoose is just a cached module, it probably makes the most sense to just require() it in again, but any one of the three methods above would work.
The modules that are included is on a file are not visible on another file. Here you can find a list of the global objects that are available on every module that you create:
https://nodejs.org/api/globals.html
All the other objects/variables that you define within a file they are defined within the context of this file. Otherwise, this could create huge problems with variables that overwrite other variables in other files and creating a mess within a project. You can think of a file like a function that includes all your code and everything that is defined in there, is not available to the global namespace.
In your case, you have to require('mongoose') in the files that you need it, and it is built like that so that can maintain the existing connection to the database.