Introduction
This article will guide you to start building up a website using Node.js using the MEAN stack. I will try to also help you with setting up your basic tools/infrastructure for developing the application like setting up node.js, mongodb, etc. I am assuming you have some basic knowledge about Node.js and JavaScript along with HTML, etc. However, even if you are new to node.js or the other technologies involved, don't worry, as the article involves a couple of different technologies, I'll just try to scratch the surface.
What does the MEAN acronym stand for?
- M - MongoDB (NoSQL document store database)
- E - Express (Web framework for use in Node.js)
- A - Angular.js (Client side JavaScript MVC framework)
- N - Node.js
The advantage of using this MEAN stack is all the components are very robust and popular and Javascript is used as the common language on both the client and server side. Also Node.js and MongoDB couple together very well.
I will define the popular technology stack below by category which is popularly used. I might not be using all the technology stated below in details but knowing the entire stack would help know what fits where.
Technology Stack Classified
Client
- HTML5/CSS3
- Angular.js as MVC framework
- Javascript/Jquery
- Bootstrap for responsive design
Server
Data Access and ORM
Database
Keep in mind that although we are using the term ORM above in Data access, these NoSQL databases don't define any schema so Mongoose might be a bit different than the other Object Relational Mappers like NHibernate or Entity Framework.
Let's Get Started
Install Nodejs
You can install Node.js from this official site http://www.nodejs.org/. Just make sure you select all the components in the Custom Setup of the install wizard.
I will be using Microsoft Web Matrix as an IDE which is free and you can install it from the below link. (You might want to choose your own IDE or even use Notepad.)
After installation, open webmatrix and you will see an interface like the one below:
Click the Options icon on the lower right corner where we will set our path to the project.
Change the Default site location to a path of your choice and click Save. The projects that you create using WebMatrix will reside on that path.
Now on the startup screen, click New and select Template Gallery. Select the Node.js tab on the left menu bar and select "Empty Site" as template. Enter a Site Name for your project too.
Click Next and WebMatrix will download the install the template for us. Now you would be able to see the Nodejs project that was created for us as shown below:
Here, we see some files like server.js, package.json, web.config, etc. We'll look into the details soon.
Firstly, open server.js file and we see that some template code is already written there as shown above. I am highlighting the piece of code which writes "Hello, world NodeJS
". Just click on Run on the top left corner and a browser will spawn up with a text of Hello World. So we have our first Node.js program up and running thereby verifying that Nodejs and webmatrix are installed properly.
Ok, so now, let's try to run our program without using WebMatrix just using our good old Command Prompt.
Open cmd
(Command Prompt in Administrator mode-Right click and Run as admin) and go to the path where the project files live. Type "node server.js
" means using node.exe, run the file server.js. Node.exe is the main executable file for running Nodejs.
And here, we get an error which is because we had run our program using matrix already and so port 8080 is already in use. I got this error while running so I am sharing it with you just in case you get it too.
Let's just change the port number to 8081 in server.js file in the last line and run the program again.
Now open a browser and browse http://localhost:8081/ and we would see the hello world again. So now, we saw that with just the command prompt, we are able to run our node.js program. We'll come back to the details of the server.js file later, but before that, let's try to get some node.js concepts cleared.
package.json
The package.json file contains information about our project like the project name, version, author, etc. It also contains a dependencies property which we'll explore later.
Modules (using require())
To follow good programming practices and write modular code, we will write our JavaScript code in different files and each file will represent a certain module.
Node.js uses a concept of requiring files (which actually represent modules) in a file so that we can use the methods of that file which we included by doing a "require
". Sounds confusing, let's do a sample.
Let's create a file and name it employee.js.
Every node.js file has something called module.exports
which is kind of an object in OOPS terms. So we can create properties using the "module.exports
" keyword.
employee.js
module.exports.firstname = "Rajiv";
module.exports.lastname = "Gogoi";
module.exports.department = "Computer Science";
module.exports.address = {
city : "Mumbai",
country : "India"
};
So this employee.js file or module contains four properties, three simple properties like firstname
, lastname
, department
and one complex property named address
.
Now let's create another file named main.js which would reference this employee.js file using the require
feature.
main.js
var employee = require("./employee.js");
console.log(employee.firstname + " " + employee.lastname);
console.log(employee.address.city + ", " + employee.address.country);
var employee = require("./employee.js");
So the above line of code uses the node.js require
method and passes in a path(./
means same directory) to the employee.js file which returns an object that we assign to the variable
employee. After that, we log the property values to the console using the employee
object.
Note: Please note here that employee.js is a file here directly under the project but we could as well create a folder and place our .js files under it and use the relative path. In larger applications, we would want to create folders and keep our related js files under folders for better management and maintenance.
Let's open up our cmd
prompt, get to the project path and try running this main.js file.
Ok, so we saw how to create a module using the require()
method and get
/set
properties. Now let's try to create another module which actually represents a class (let's get more closer to OOPS).
Let's create a file customer.js that has the code below. This piece of code will return a function which we will simulate as a Class
. For those who know constructor functions in JavaScript, the usage below is the same. http://www.javascriptkit.com/javatutors/oopjs2.shtml
module.exports = function () {
this.customername = "TopBank",
this.location = "Florida",
this.employeestrength = 10000
};
Now let's go to our main.js file again and write the following piece of code below that was already written above.
We'll use require
as before, but this time, it will return a function which will represent the Customer
class. After that, we will create an object of the Customer
class using the new
keyword.
var employee = require("./employee.js");
console.log(employee.firstname + " " + employee.lastname);
console.log(employee.address.city + ", " + employee.address.country);
var Customer = require("./customer.js");
var objCustomer = new Customer();
console.log(objCustomer.customername);
console.log(objCustomer.location);
console.log(objCustomer.employeestrength);
Node Package Manager(NPM)
NPM is a functionality by which we can install node.js packages from the internet. For those coming from the .NET background, it's similar to Nuget. We have similar package managers for Java too e.g.jpm4j.
https://www.npmjs.org/ lists out the libraries available in node.js for us to use.
Now, let's install Node.js express library, yes the E from the MEAN acronym using npm
using the following command:
npm install express --save
Here --save
is optional which actually mentions that please go ahead and save express library as a dependant library for the current project. The effect is in the package.json file (in the main project folder), we will have a dependencies
property with express as the value. The benefit is that when we will use source control, we don't have to checkin these npm
modules there. Whenever a new user will checkout the node.js project, the package.json file will see the npm
dependencies and install them.
After installation, we will see that in our project folder, we will have a new folder node_modules which will contain the express library files.
The beauty of npm
is it does dependency management for child libraries too, e.g., our express module might also depend on some other modules. So the way it will work is the express folder under node_modules folder will also have a package.json file where it will again define the dependencies.
server.js
Ok, so sometime before, we saw our server.js file returning a "Hello World
" response to our browser. Now let's try to get into the details of this file and try changing it a bit and get some explanation of what each line does.
var http = require('http');
var server = http.createServer(function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.write("Hello Node.js, are you running fine on host " + req.headers.host + "\n");
res.end();
})
server.listen(process.env.PORT || 8081);
Let's Get Started
Now that we have setup node.js, gained some basic concepts and run some programs, let's try to build something using the MEAN stack as promised.
We have already installed the "Express
" library above using npm
. The "Express
" library will help us build our web server in a relatively easier way because it will serve as our web framework. So we will have library functions to do most of the stuff like HTTP GET
/POST
, etc., send data to the client and won't have to deal with things like res.end()
for manually ending the response. Instead, Express library will act as an abstraction layer so that we can concentrate on our application logic and not have to deal with lower level responsibilities. So let's modify the server.js file to use the Express library.
var http = require('http');
var express = require('express');
var application = express();
application.get("/", function (req, res) {
res.set("Content-Type", "text/html");
res.send("Hello using express get");
})
var server = http.createServer(application)
server.listen(process.env.PORT || 8081);
Now let's try to run our program, either click Run on the top left of Web matrix or use the command prompt to run the node server.js file. In either case, you will see the browser, displaying the Hello text sent back from the server.
View Engines
Till now, we were sending text/html from the server directly using write()
or the send()
function, but in real life applications, we would want to use a view engine where we can write our HTML. Node.js has different view engines like Jade, EJS or Vash and what to choose is entirely upon the syntax taste that pleases one. For this article, I will be using the Vash view engine.
Let's install the vash
library using the following command:
npm install vash --save
Now that vash
is installed, let's re-write our server.js file to use the vash
view engine and set the response to render a view.
server.js
var http = require('http');
var express = require('express');
var application = express();
application.set("view engine", "vash");
application.get("/", function (req, res) {
res.render("index", {firstname: "Robert", lastname: "Brosnan"});
})
var server = http.createServer(application)
server.listen(process.env.PORT || 8081);
After that, let's create a views folder directly under the project. This views folder will contain the views files. Let's add an index.vash file and add the following piece of code.
index.vash
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
@model.firstname @model.lastname
</body>
</html>
Notice we are using the firstname
and lastname
properties by appending after @model
. Yes, the view treats these properties which are passed to it as model properties.
<meta charset="utf-8" /> <title></title>
Now let's run the program again and we should see the output of Robert Brosnan.
<meta charset="utf-8" /> <title></title>
Adding CSS Resources
Let's add a site.css file to our project to do the styling. We already have a public folder in the main project directory. Let's create the site.css file in that directory. This public folder is the place where all client side static resources should live like CSS, client side .js files, images, etc.
site.css
body {
background-color: #b6ff00;
}
Link the site.css file in the index.vash view:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title></title>
<link href="site.css" rel="stylesheet" />
</head>
<body>
@model.firstname @model.lastname
</body>
</html>
Now if we run our site again using the Run button from within WebMatrix, we should see a background color which means the site.css is being used. However, if we try running our node server using the command prompt, going to our project path and doing "node server.js
", and then try running the site from a browser, we will notice that we don't see the background color. If we use developer tools in the browser(F12), we can see that the site.css is not found.
So why do we have a difference when we try running the site directly from WebMatrix and when we try to run the node server from command prompt? Why when we run the site from WebMatrix, it's able to find the site.css find within the public folder.
The reason is because, when we run the site from WebMatrix, it uses IISExpress to host the node server and IISExpress uses a configuration file web.config which you might have noticed in the project directory already.
Please note that this web.config file is not necessary to run node.js and only the WebMatrix IDE created this file to host it in Microsoft IIS web server (IISExpress in our case). When we run the node.js server using command prompt, it doesn't read the web.config.
If we have a look at the web.config file, we can see that there is a rule set which sees the incoming url that matches a physical file in the public folder. So this rule effectively helps our request find the site.css file inside the public folder.
But does it mean that when we run the node server using command prompt, we won't be able to use CSS files, obviously not. To identify the public folder, when we run using command prompt, we need to set the public folder as the static resources folder. To do that, open the server.js file and write the following line of code after the line of code setting the view engine. I have also used console.log
to print the __dirname
so you can see that it points to the physical directory of our node.js project.
application.set("view engine", "vash");
console.log(__dirname);
application.use(express.static(__dirname + "/public"));
So now when we run our project, we should see our beautiful background in the browser. :)
Bower For Front End Package Management
Just like we are using npm
for server side package management, we will use a client side package manager named "Bower
" for installing the client side resources like jquery, bootstrap, knockout, angular, etc.
So let's first install Bower using the following npm
command.
npm install bower --save-dev
Notice the use of this new optional flag --save-dev
. This means this is only a development dependency and we don't need this package on the production server. Of course, why will we need a client side package manager on our production server.
See the package.json file in the below snapshot.
To use bower, we need a configuration file named .bowerrc where we will put a json indicating where to save the client side resources. So let's create a new file under the project directory and name it .bowerrc and paste the following piece of json.
So this piece of json tells bower to install the client side resources in the public lib folder.
Now that we have configured bower, let's use it to install jquery.
We will notice that jquery is downloaded in the public/lib directory.
Tips and Tricks
Till now, we had to manually restart our node.js application every time we made changes in our server side code so that the changes get reflected. However, there is a node.js development utility available named "nodemon
" which monitors changes in the node application and automatically restarts the server. Cool isn't it, so now we save some time in not having to restart our server after new changes.
To install nodemon
, let's use the following command:
npm install nodemon -g
This time we introduced another switch -g
which means install globally so that nodemon
will be available for all node.js projects on this machine not only our current project.
Now let's run our server.js file but this time using nodemon
.
nodemon server.js
Now try to make any changes to the server side code like changing the firstname
property, etc. and refresh the browser and you will be delighted to see the changes instantly. :)
REST Service
Now that we have ran a couple of node.js programs, used vash
as the view engine, decorated with CSS, etc., let's build up a REST service to be consumed later by a client side library Angular.js.
Let's first create a controllers folder inside our node project. We are calling the folder controllers because it will be controlling the request to get some model(data) and return to the view, yes the C of the MVC design pattern.
Inside the controllers folder, let's create a JavaScript file named employeeController.js. This file will be the main file for our application which we will use to display employees
and insert employees
. Yes, that's the piece of functionality we will be building using the MEAN stack. We will be using a JavaScript self executing anonymous function to keep the code readable and modular. To learn more about self executing anonymous functions, you can go through http://esbueno.noahstokes.com/post/77292606977/self-executing-anonymous-functions-or-how-to-write.
Before our REST service starts returning json, etc., let's try to do something simpler what we were doing before, i.e., returning the view index.vash but by using the employeeController
.
(function (employeeController) {
employeeController.init = function(application){
application.get("/", function(req, res){
res.render("index", {firstname: "John", lastname: "Brosnan"});
})
}
})(module.exports);
And we'll have to change our server.js file to make a call to the employeeController
's init
function. And we of course, don't need the call to application.get()
in the server.js file because we moved that piece of code to the employeeController.js init
method.
var employeeController = require("./controllers/employeeController");
employeeController.init(application);
Now if we try to run our application, we should see the same output in the browser, but this time we used a controller to handle the GET
request and return the response to the view.
Let's now modify our employeeController.js file to expose an API endpoint which accepts a GET
request and returns some json as data. This is actually simple, what we have to do is in the application.get()
function, we have to return json using the send
function instead of using the render()
function which actually renders a view.
(function (employeeController) {
employeeController.init = function (application) {
application.get("/", function (req, res) {
res.set("Content-Type", "application/json");
res.send({employeeName: "Tommy Jones"});
})
}
})(module.exports);
Now try running the applicaiton and we will see json data being returned.
Let's Get Angular
AngularJs is a client side data binding library similar to KnockoutJs if you have used it. I won't go into the details of Angularjs here as there are many tutorials on the internet. What I'll be doing is just show a sample of how to use AngularJs with Node.js.
So let's first install Angularjs using the bower
tool with the following command:
bower install angular-bootstrap
This will install both angular and bootstrap library (for responsive UX design).
Now let's include the angular and bootstrap script in our index.vash file.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
@model.firstname @model.lastname
<script src="/lib/jquery/dist/jquery.js"></script>
<script src="/lib/angular/angular.js"></script>
<script src="/lib/angular-bootstrap/ui-bootstrap.js"></script>
</body>
</html>
Let's create a folder named scripts under our public folder which will contain our client side JavaScript files.
And we'll add a file named empViewdata.js. This file contains a JavaScript self executing anonymous function, yes same pattern that we used for the server side scripts. It contains the angular module which we are naming "empViewdata
" and the angular controller named "empController
". To the self executing function, we are passing the window.angular
object so that we can start using angular library functions. The angular module is a piece of modular code, which defines the dependencies of the module and contains the controllers.
(function (angular) {
var module = angular.module("empViewdata", []);
module.controller("empController",["$scope",
function($scope){
$scope.employees = [{name: "Roger Peter"},
{name: "Lovely Planet"},
{name: "Roudie Moore"}]
}
])
})(window.angular);
$scope
is an object that Angular provides which we can use to return the data to the view. In a later part, we'll see the usage of another such angular object named $http
.
So we have our Angular module and controller ready to return the viewmodel
data using the $scope
object, let's write our view to use the Angular objects so that the view can do data binding using Angular.
index.vash
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title></title>
<link href="site.css" rel="stylesheet" />
</head>
<body>
<div ng-app="empViewdata">
<div ng-controller="empController">
<div ng-repeat="e in employees">
{{ e.name }}
</div>
</div>
</div>
<script src="/lib/jquery/dist/jquery.js"></script>
<script src="/lib/angular/angular.js"></script>
<script src="/lib/angular-bootstrap/ui-bootstrap.js"></script>
<script src="/scripts/empViewdata.js"></script>
</body>
</html>
<script src="/lib/jquery/dist/jquery.js"></script><script src="/lib/angular/angular.js"></script><script src="/lib/angular-bootstrap/ui-bootstrap.js"></script><script src="/scripts/empViewdata.js"></script>
View angular attributes explanation:
ng-app
--> This angular attribute will contain the value of an angular module in our case "empViewdata
" which we wrote earlier. Effectively, this div
will be the container within which our angular objects will reside. We can have multiple ng-app
attributes on a single page so that different sections of the page can be assigned different tasks by assigning to different angular modules. ng-controller
--> This angular attribute will be responsible for controlling the view actions like serving data to a view, handling events like click, dropdown change, etc. In our case, the controller name is "empController
" which is sending the viewmodel
to the view. Just like ng-app
, there can be multiple controllers in a view doing different actions. Please note that this is the client side controller for angular to use. The server side controller that we created earlier "employeeController
" is the node.js controller which handles HTTP GET
/POST
requests from the browser. ng-repeat
--> This attribute specifies that this <div>
will repeat number of times to the value of items in the collection. It is similar to a foreach
loop that many languages like C#, JavaScript, have. The expression "e in employees
" means e
is a local variable that will execute each time in the loop and employees
is a collection. We already saw that the $scope
, employees
contains a number of employee
names in an array. So we are essentially trying to loop through the employees
collection. {{ e.name }}
--> The double curly braces syntax means, we would like to bind some data within it. Here using our local variable e
, we are displaying the name of the employee(e.name)
.
So that's it for the view. Ok, so now, let's just change the server side node.js controller employeeController
to render our initial index.vash view instead of a json response.
res.render("index");
Now try running the site using a browser and you will be able to view the employee
names.
Ok, so we used angular to return a hard coded collection of employee
names and display it to the view. But in a real world application, that data will be coming from some data source and being served by some service. So let's resume our work back to the REST service that we created earlier.
We'll add another GET
event handler to the employeeController.js file as shown in the code snippet below. This get
handler will route to url requests "/api/employee" and will return a json collection of employee
names.
(function (employeeController) {
employeeController.init = function (application) {
application.get("/", function (req, res) {
res.render("index");
})
application.get("/api/employee", function (req, res) {
res.set("Content-Type", "application/json");
res.send([{ name: "Roger Peters" },
{ name: "Lovelys Planet" },
{ name: "Roudie Moores"}]);
})
}
})(module.exports);
And back to our angular module, where we'll do an ajax HTTP GET
call to this "/api/employee" which will return a json collection and we'll happily bind it using angular as done before but this time not with a hard coded collection but data returned from a REST service. To achieve this, we'll use the $http
angular object and make a get()
request similar to the jquery get request to the url "/api/employee
". $http
uses something called a JavaScript promise pattern which is kind of a callback we define on the then()
method. Then then()
method takes 2 functions as parameters, one for success and the second for failure.
Learn more about JavaScript promises https://www.promisejs.org/:
(function (angular) {
var module = angular.module("empViewdata", []);
module.controller("empController", ["$scope", "$http",
function ($scope, $http) {
$http.get("/api/employee")
.then(function (result) {
$scope.employees = result.data;
},
function (error) {
alert("error");
});
}
])
})(window.angular);
Now, let's try running our site again and we should see the employee
names returned by the node.js REST service and data binded with angular.
Ok, so we are now left with only the "M (MongoDB)" of the MEAN stack. We already used E (Express), A (Angular), N (Node.js), so let's get mongodb :)
MongoDb
Let's download mongodb from https://www.mongodb.org/downloads based on our operating system. And after extracting from the zip file, let's copy the files from the bin directory to one of the directories for our project to use.
Let's also create a folder inside this directory and name it database. This folder will be the container for the data.
Now let's run a command from our cmd to run our mongodb server.
Now our mongodb server is up and running. Let's try browsing our mongodb server using a browser, yes mongo web console runs on port 28017.
We'll use mongoose as for our data connection between node.js and mongodb. In short, mongoose is sort of an ORM like nhibernate/entity framework using which we can define schemas for our models. Just for our knowledge, MongoDB being a NoSQL database doesn't enforce schemas, but that's another topic though which we'll not discuss here.
Let's install mongoose
using the following command:
npm install mongoose.
Now let's write code in our employeeController.js to use mongoose
to connect to our mongodb
database, create an employee
, and retrieve the employee
s.
employeeController.js
We added the post event handler to this file to handle creation of an employee
.
(function (employeeController) {
employeeController.init = function (application) {
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/empdb');
var db = mongoose.connection;
db.on('error', console.error);
db.once('open', function callback() {
console.log('mongodb connection opened.');
});
var empSchema = mongoose.Schema({ name: String });
var Employee = mongoose.model('Employee', empSchema);
application.get("/", function (req, res) {
res.render("index");
})
application.get("/api/employee", function (req, res) {
res.set("Content-Type", "application/json");
Employee.find(function (err, employees) {
if (err) return console.error(err);
res.send(employees);
});
});
application.post("/api/employee", function (req, res) {
var emp = new Employee({ name: req.body.empName });
emp.save(function (err, emp) {
if (err) return console.error(err);
console.log(emp);
});
res.set("Content-Type", "application/json");
res.send({ name: req.body.empName });
});
}
})(module.exports);
empViewdata.js
(function (angular) {
var module = angular.module("empViewdata", []);
module.controller("empController", ["$scope", "$http",
function ($scope, $http) {
$scope.newEmployee = { empName: "" };
$http.get("/api/employee")
.then(function (result) {
$scope.employees = result.data;
},
function (error) {
alert("error");
});
$scope.create = function () {
$http.post("/api/employee", $scope.newEmployee)
.then(function (result) {
$scope.employees.push(result.data);
})
};
}
])
})(window.angular);
Change index.vash to include a textbox
and a submit
button to add employees
.
ng-submit
--> This takes a create
method which we have defined on our empViewdata.js which makes an $http.post
call to the node.js REST service API. ng-model
--> It defines a model object to be passed as the body of the HTTP POST
request. Contains the properties which are defined on the HTML elements, in our case only one, the text box.
<div ng-app="empViewdata">
<div ng-controller="empController">
<form class="form-horizontal" name="empForm" ng-submit="create()">
<div class="form-group">
<input type="text" id="empName" ng-model="newEmployee.empName" />
<input type="submit" class="btn btn-primary" value="Create" />
</div>
</form>
<div ng-repeat="e in employees">
{{ e.name }}
</div>
</div>
</div>
And one last thing, change server.js to include node.js library body-parser
which would be able to handle POST
requests.
var express = require('express'),
bodyParser = require('body-parser');
application.use(bodyParser());
Now make sure both the mongodb and node.js server are running, and browse the site. You should be able to view the list of employees and also be able to create employees.
Summary
So in this article, we explored briefly how we can use the MEAN stack to build websites using node.js at the server side. Hope I was able to share my knowledge and it was helpful. Please feel free to ask any questions, I'll try my best to answer your questions. Thanks and keep learning. :)
History
- 7th September, 2014: Initial version