Want to get crystal clear about NodeJS app structure (Full JavaScript Stack) [closed] Want to get crystal clear about NodeJS app structure (Full JavaScript Stack) [closed] mongodb mongodb

Want to get crystal clear about NodeJS app structure (Full JavaScript Stack) [closed]


Alright, this is a pretty broad question and I'm definitely no expert, but I'll do my best here.

TL;DR

  • routes are controllers that tell what logic to execute when a user navigates their browser to a certain path within your app, including which views to render and what data to send to those views
  • models are just that - data models within your application
  • module.exports = tells a file what exactly it "exports", that is what code needs to be executed or accessible from your main app file.
  • require(..) includes a module. You can set this on a variable so that you may call module functions later, or simply execute a function if that is all that module.exports returns.

Combining these techniques can help you nail down a solid framework for any of your applications.


Long Answer

Express provides a solid framework for structuring your Node.js application. Node is completely independent of Express, but because of how popular Express is they practically go hand-in-hand. Once installed, Express can be used to generate a scaffold web project (with options) for you to build on top of if you'd like.

Controllers

A generated project will create /routes/index.js, which (if you understand MVC) is essentially your main controller. A route in express is written as so:

app.get('/path', function(req, res, next){ .. } );

Lets break that down: our application variable (app) is being told that on a GET request to '/path' to execute an anonymous callback function with req, res, next variables (request, response, callback respectively). I find it helpful to think of this like a custom event handler.

Its important to note at this point that we could also call app.post with the same syntax for posts to a URL as opposed to gets.

Within our anonymous callback, we handle any incoming data and render a view for the user. This is where most of my business logic ends up, so it actually makes sense to NOT use anonymous functions here. Here's an example of a basic callback that just displays a homepage:

app.get('/', function(req, res, next){    //some business logic    res.render('views/home');});

When the user tries to GET the index path of our application (/), we simply render our home view that, from the root of our project, is stored in a views folder.

But what if we want to modularize this so that we aren't declaring all of our routes in our main app.js or server.js?

We use module.exports = .. in our modules to tell our server what exactly to include. In my controller, I export a single function that takes the application as an argument and uses that to define our routes like so:

Controllers/User.js

 module.exports = function(app){    app.get('/users', function(req, res){        var users = req.db.collection('users').find();        if (!users) {            console.log("no users found");            res.redirect('/');        } else {            res.render('users/index', {users : users});        }    });};

Don't worry about the req.db code, I attach the database to the request in my application but that isn't done by default. Simply understand that I'm getting a list of 'users' here, and redirecting the user to the index of my app if there aren't any.

Models

Mongoose provides us with a great interface for writing models. With mongoose, writing models is a three step process:

  • Define a schema
  • Define model logic
  • Generate and export the model

Here is an example of a User model:

Models/User.js

var mongoose = require('mongoose'),    userSchema = new mongoose.Schema({        name: { type: String, required: true },        joinDate: {type: Date, default: date.now }    }),    User = mongoose.model('user', userSchema);module.exports = user;

Server App

module.exports is used to help us define some modularity to our codebase. When we run a node application, we're ultimately running a single JavaScript file (you've already seen that file with server.js or app.js).

To keep this file from getting too big with multiple models and routes, we use require(module) to include code from other JS files. module in our case would be a path to the module we want to require. If you have the following doc structure:

| Controllers    - User.js| Models    - User.js| Viewsapp.js

To include your user controller from app.js, you would write: require('./Controllers/User'). Since our controller modules simply export functions, we can call that function immediately after our require statement by simply adding parentheses at the end (with whatever parameters are required). Including my controllers looks like so:

require('./Controllers/User')(app)

I'm passing in the actual app, because my module (below) simply exports a function that adds business logic to my app's routes. This only needs to be called and never used, so I don't capture my controller as a variable to call methods on later.

Including models is a little different, since we may want to perform some operation that our model defines. We can do this by changing up our require code just a bit:

var User = require('./Models/User');

Now we can call methods of our User model whenever. Mongoose gives us a lot of base functionality for free:

User.find({}, function(err, users){ .. });

The above function will go find all of our users, and then execute an anonymous function with a potential err (is null if no issues) and then a list of our users in JSON format. Pretty nifty.

Combining all of these concepts is how you create a basic web application using Express and Node.js. Please let me know in the comments if there's anything I can clarify about how I use Express. This is very surface level knowledge, and I suggest digging into documentation and looking at plugins to extend the capabilities of your apps. Good luck!