Node.js is a backend javascript engine. Express is a lightweight web framework that sits on top of Nodejs. In this post, I am going to go build a RESTful app talking steps at a time. Down the road, I will use Semantic-UI as a CSS alternative to Bootstrap. I am going to use MongoDB as the database engine.

The App should allow users to enter name of a mosque, its image and a short description. The user can update and delete entered information later. So, let us get started!

Installation

I have a mac, and homebrew did everything for me. I assume you will manage with your own environment. Googling and little bit of patience will solve all problems. Stackoverflow community will be able to address your particular issues. Make sure that when type node -v you get a version number, which assures you that you are ready to go.

initialize npm

Create a directory mosques.

baqi:udemy abaqi$ mkdir mosques
baqi:udemy abaqi$ cd mosques

Now initialize npm. A wizard will take you through few options and result in a package.json file for you in the directory.

baqi:mosques abaqi$ npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help json` for definitive documentation on these fields
and exactly what they do.

Use `npm install <pkg> --save` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
name: (mosques) 
version: (1.0.0) 
description: a minimalist RESTful app about Mosques
entry point: (index.js) app.js
test command: 
git repository: 
keywords: 
author: Baqi
license: (ISC) 
About to write to /Users/abaqi/udemy/mosques/package.json:

{
  "name": "mosques",
  "version": "1.0.0",
  "description": "a minimalist RESTful app about Mosques",
  "main": "app.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Baqi",
  "license": "ISC"
}


Is this ok? (yes) 
baqi:mosques abaqi$ 

Now, install express:

npm i express --save

The --save above will append the express in the dependency list of the package.json file.

baqi:mosques abaqi$ cat package.json 
{
  "name": "mosques",
  "version": "1.0.0",
  "description": "a minimalist RESTful app about Mosques",
  "main": "app.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Baqi",
  "license": "ISC",
  "dependencies": {
    "express": "^4.16.2"
  }
}

app.js : the first version

The bare minimum is:

  1. get the express framework
  2. create a route
  3. make the app run on a port

Here is how it looks.

app.js

var express = require('express');
var app = express();

app.get('/', function(req,res){
	res.send('..just the first step in a 1000 mile journey..');
});

app.listen(3000,function(){
	console.log('server started on port 3000..');
})

And here is how to run it:

baqi:mosques abaqi$ node app.js 
server started on port 3000..

Then go to your browser and open up: http://localhost:3000/.

gdp per capita figure 1: First skeleton

You can always ctrl+c in the terminal to stop the app.

templates

Instead of getting result through res.send(), we want to use templates. To do that we need to create a folder called views and create the template file inside it. Let us call it index.ejs. Node files must have ejs extension. Inside it we will have normal html codes.

baqi:mosques abaqi$ mkdir views
baqi:mosques abaqi$ touch views/index.ejs

In order for express to serve templates we have to install ejs module from npm.

npm install ejs --save

Here is about first template.

index.ejs

<!DOCTYPE html>
<html>
<head>
	<title>Mosques around the World</title>
</head>
<body>
<h1>Houses of Allah</h1>

<p>This Site will list amazing photoes of mosques around the world. Stay tuned!</p>
</body>
</html>

Now, go to your app.js and change the ‘req.send(…)’ to req.render('index.ejs').

app.js

var express = require('express');
var app = express();

app.get('/', function(req,res){
	res.render('index.ejs');
});

app.listen(3000,function(){
	console.log('server started on port 3000..');
})

view engine

One small enhancement: over time you might get bored by typing ejs file extension every time in the req.render function.

All you need is to insert app.set('view engine', 'ejs'); in your app.js file, and then get rid of .ejs every time. Here is the updated app.js

app.js

var express = require('express');
var app = express();

app.set('view engine', 'ejs');

app.get('/', function(req,res){
	res.render('index');
});

app.listen(3000,function(){
	console.log('server started on port 3000..');
})

Now, go and restart the app. (that means first ctrl+c to stop the app if running, then run again through node app.js). Here is the shape of our app so far.

gdp per capita figure 2: incorporating ejs templates

RESTful routes

It is good practice to follow the following routing convention.

URL HTTP Verb Action
/mosques/ GET index
/mosques/new GET new
/mosques POST create
/mosques/:id GET show
/mosques/:id/edit GET edit
/mosques/:id PATCH/PUT update
/mosques/:id DELETE destroy

Let us pick the first route, i.e., /mosques. It means when I point to this url, it should render the index.ejs templates we just have created. and when user visits the / path it should redirect me to the /mosques path.

gdp per capita figure 3: the /mosques route

app.get('/', function(req,res){
	res.redirect('/mosques');
});

app.get('/mosques', function(req,res){
	res.render('index');
});

Next, the /mosques/new route should lead me to a template (which is not yet created) called new.ejs, and so on, I should have show.ejs and edit.ejs for the routes /mosques/:id and /mosques/:id/edit respectively.

app.get('/mosques/new', function(req,res){
	res.render('new');
});

app.get('/mosques/:id', function(req,res){
	res.render('show', {id:req.params.id});
});

app.get('/mosques/:id/edit', function(req,res){
	res.render('edit',{id:req.params.id});
});

The html verb that are not get will not have their own template, and will spend more time with them later.

Here are rendering of these files in the browser with just a placeholders for the time being.

gdp per capita figure 4: the /mosques/new route

gdp per capita figure 5: the /mosques/:id show route

gdp per capita figure 6: the /mosques/:id/edit route

Mystery of :id

: allows us to pass parameters within the requested url. Each mosque will have an id in our future mongoDB database. So, when we visit the url /mosques/123endb34nd, our app will show detailed information about the mosque which has id of 123endb34nd.

The way to grab that id from url is through req.params.id as we will see later.

Here is the show.ejs file and note how I am grabbing the id in the template using the ejs way <%=id%>.

show.ejs

<h1>Mosque Information</h1>

<p> Here you will see a form to show detailed 
information about the mosque with id <%=id%>
</p>

Partials

The various ejs files entails us to have partials of header and footer, where we can move common stuff there and have our ejs files just include them. In this way we save much time and have less pain when modifying things.

Here are the header.ejs and footer.ejs files saved inside views/partials folder.

baqi:mosques abaqi$ mkdir views/partials
baqi:mosques abaqi$ touch views/partials/header.ejs
baqi:mosques abaqi$ touch views/partials/footer.ejs

header.ejs

<!DOCTYPE html>
<html>
<head>
	<title>Mosques around the World</title>
</head>
<body>

footer.ejs

Copyright 2017
</body>
</html>

All we need is to include these files in our rest of the files. Here is an example from index.ejs

index.ejs

<% include ./partials/header %>
<h1>Houses of Allah</h1>

<p>This Site will list amazing photoes of mosques around the world. Stay tuned!</p>

<% include ./partials/footer %>

Semantic-UI

Let us give some sleek look to our site by using Semantic-UI. We will include the following cdn in our header.ejs file.

https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.2.13/semantic.min.css

I am adding a simple navigation in the header.

header.ejs

<!DOCTYPE html>
<html>
<head>
	<title>Mosques around the World</title>
	<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.2.13/semantic.min.css">
</head>
<body>
     <div class="ui fixed inverted menu">
         <div class="ui container">
             <div class="header item">
                 <i class="large world icon"></i>Mosques
             </div>
             <a href="/" class="item">Home</a>
             <a href="/mosques/new" class="item">New Mosque</a>
         </div>
     </div>

Here is how it looks.

gdp per capita figure 7: we need to fix the problem of margin

The text need to move a bit below. That means we need to increase the margin to container class. This need to be done through custom css. To do that, we us adopt good practice and create a folder /public/stylesheets and place app.css file inside it.

baqi:mosques abaqi$ mkdir public
baqi:mosques abaqi$ mkdir public/stylesheets
baqi:mosques abaqi$ touch public/stylesheets/app.css

And then introduce the margin in the css file.

app.css

.container.main{
    margin-top: 7.0em;
}

In order for this to work, we need to do two things:

1.incorporate this file in the header.ejs file

<link rel="stylesheet" type="text/css" href="/stylesheets/app.css">

2.make the app use the public directory as our static asset folder.

app.use(express.static('public'));

Now we have a better page.

gdp per capita figure 8: custom css

MongoDB

After building the skeleton, let us start including our mongoDB stuff. I assume you installed it in your environment. Make sure the deamon is running and that when you type mongo in the terminal you end us in the mongo console.

Once installed, you need to install mongoose for express.

baqi:mosques abaqi$ npm install mongoose --save

Then make app.js have it.

var express = require('express');
var app = express();
var mongoose = require('mongoose');
mongoose.Promise = global.Promise;

app.set('view engine', 'ejs');
app.use(express.static('public'));

mongoose.connect('mongodb://localhost/mosques_app', {useMongoClient: true});
//rest of the file

Next, we need to define the schema, and create a Mosque object in the app.js file. As you can see, my mosques will have a name, image url, location, a short description, when it was built, and when this mosque entered into the database (which is defaulted to the time of creation).

var mosqueSchema = new mongoose.Schema({
    name: String,
    image: String,
    location: String,
    description: String,
    established: String,
    created: {type: Date, default: Date.now}
});

var Mosque = mongoose.model("Mosque", mosqueSchema);

Just as a starter, let us create the first two mosques.

Mosque.create({
	name: "Zaid Mosque",
    image: "https://source.unsplash.com/ERLAcTp-8MQ",
    location: "Abd Dhabi, Emirates",
    description: "The Grand Mosque was constructed between 1996 and 2007. It was designed by Syrian architect Yousef Abdelky",
    established: "2007",
});

Mosque.create({
	name: "Medina Mosque",
    image: "https://source.unsplash.com/jQUB81i93po",
    location: "Medina, Saudi Arabia",
    description: "The most important mosoque after Makkah. Built by Prophet of Islam. It has beautiful greem dome on top of the grave of Prophet.",
    established: "580AD"
});

Let us make sure it was created. Log to mongo console and follow the commands: show dbs, use mosques_app, show collections, db.mosques.find().

baqi:mosques abaqi$ mongo
MongoDB shell version v3.4.10
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.4.10
...
...
> show dbs
admin        0.000GB
cat_app      0.000GB
demo         0.000GB
local        0.000GB
mosques_app  0.000GB
yelp_camp    0.000GB
> use mosques_app
switched to db mosques_app
> show collections
mosques
> db.mosques.find()
{
"_id" : ObjectId("5a3660fe7be2af6b2a734355"), 
"name" : "Zaid Mosque", 
"image" : "https://source.unsplash.com/ERLAcTp-8MQ", 
"location" : "Abd Dhabi, Emirates", 
"description" : "The Grand Mosque was constructed between 1996 and 2007. It was designed by Syrian architect Yousef Abdelky", 
"established" : "2007", 
"created" : ISODate("2017-12-17T12:20:14.401Z"), 
"__v" : 0 }
{ "_id" : ObjectId("5a3751286b994671f09c363b"), "name" : "Medina Mosque", "image" : "https://source.unsplash.com/jQUB81i93po", "location" : "Medina, Saudi Arabia", "description" : "The most important mosoque after Makkah. Built by Prophet of Islam. It has beautiful greem dome on top of the grave of Prophet.", "established" : "580AD", "created" : ISODate("2017-12-18T05:24:56.578Z"), "__v" : 0 }

Show Route

Now let me revisit the /mosques show route and bring the data from mongo database. To do that we need to use Mosque.find method as follows.

app.get('/mosques', function(req,res){
	Mosque.find({}, function(err,mosques){
	if(err){
 	console.log('error:');
 	console.log(err);
 	} else {
 	res.render('index', {mosques: mosques});
 	}
	});
});

Let us present these two mosques in a nice format in the index.ejs utilizing semantic-UI features.

index.ejs


<% include ./partials/header %>
<div class="ui main text container">
    <div class="ui huge header">Mosques Around the World</div>
    <div class="ui top attached segment">
        <div class="ui divided items">
             <% mosques.forEach(function(mosque){%>
                <div class="item">
                    <div class="image">
                        <img src="<%=mosque.image%>">
                    </div>
                    <div class="content">
                        <a class="header" href="/mosques/<%=mosque._id%>"><%=mosque.name%></a>
                        <div class="meta">
                            <span><%=mosque.created.toDateString()%></span> | Established <span><%=mosque.established%></span>
                        </div>
                        <div class="description">
                            <p><%-mosque.description.substring(0,100)%>...</p>
                        </div>
                        <div class="extra">
                            <a class="ui floated basic violet button" href="/mosques/<%=mosque._id%>">Read More <i class="right chevron icon"></i></a>
                        </div>                  
                    </div>
                </div>
            <%});%>
        </div>
    </div>
</div>
<% include ./partials/footer %>

Few points to note: We are looping through the mosques data using forEach function in javascript. Since the description is long, we are using substring(0,100) to only include the first 100 characters. Note that <%- ... %> allows the text to apply any html tags within. Finally note that .toDateString() presents dates in a more readable format.

gdp per capita figure 9: Show page polished

Show detailed page route

Now we move to the /mosques/:id route, where we need to show full page of a particular mosque retrieved by its id in the mongo database.

Here is the code.

app.get('/mosques/:id', function(req,res){
	Mosque.findById(req.params.id, function(err,foundMosque){
		if(err)
			{console.log(err);
			    res.redirect('/mosques');
			} 
		else {
			res.render('show', {mosque: foundMosque})
		}
	});
});

Note how we use Mosque.findById() and pass ID from the url. Here is how format our show.ejs file.

show.ejs

<% include ./partials/header %>
<div class="ui main text container segment">
    <div class="ui huge header"><%=mosque.name%></div>
    <div class="ui top attached">
        <div class="item">
            <img class="ui centered image rounded" src="<%=mosque.image%>">
            <div class="content">
                <div class="meta">
                            <span><%=mosque.created.toDateString()%></span> | Established <span><%=mosque.established%></span>
                        </div>
                <div class="description"><%-mosque.description%></div>
                <form id="delete" action="/mosques/<%=mosque._id%>?_method=DELETE" method="POST">
                    <button class="ui basic red button">Delete</button>
                </form> 
                <a class="ui basic green button" href="/mosques/<%=mosque._id%>/edit">Edit</a>
            </div>
        </div>
    </div>
</div>
<% include ./partials/footer %> 

We borrowed many styling arrangements from the previously seen index page. We have added buttons for edit and delete which we will talk about later. The important point is to see how to pass delete route in the form of a form which I will discuss in the next section.

<form id="delete" action="/mosques/<%=mosque._id%>?_method=DELETE" method="POST">
                    <button class="ui basic red button">Delete</button>
</form> 

Here is our page:

gdp per capita figure 10-a: Show detailed page- we have to align the two buttons

Note how the delete button is taking the entire line. In order to bring the edit button in the same line, we need to add the following css code to the delete button through its id #delete.

#delete {
    display: inline;
}

gdp per capita figure 10-b: Show detailed page - much better!

Ladies and gentlemen, here comes forms

With forms a new set of installations and configurations need to be done.

First we need to install body-parser to enable extracting data from form, also we need express-sanitizer to prevent inserting harmful codes through forms. Finally, we also need method-override to allow creating DELETE and PUT routes as we will see.

baqi:mosques abaqi$ npm install body-parser method-override express-sanitizer --save

Then we configure our app.js to use these packages.

var express = require('express');
var app = express();
var expressSanitizer = require('express-sanitizer');
var bodyParser = require('body-parser');
var mongoose = require('mongoose');
var methodOverride = require('method-override');

mongoose.Promise = global.Promise;

app.use(express.static('public'));
app.use(bodyParser.urlencoded({extended:true}));
app.set('view engine', 'ejs');
app.use(methodOverride('_method'));
app.use(expressSanitizer());
...
...

The Edit route (/mosques/:id/edit)

First we create the get route as follows.

app.get('/mosques/:id/edit', function(req,res){
    Mosque.findById(req.params.id, function(err,foundMosque){
		if(err)
			{console.log(err);
			    res.redirect('/mosques');
			} 
		else {
			res.render('edit', {mosque: foundMosque});
		}
	});
});

Then, we go and create the edit.ejs page which will contain our form.

edit.ejs

<%include ./partials/header %>

<div class="ui main text container segment">
    <div class="ui huge header">Edit "<%=mosque.name%>"</div>
    <form class="ui form" action="/mosques/<%=mosque._id%>?_method=PUT" method="POST">
        <div class="field">
            <label>Name</label>
            <input type="text" name="mosque[name]" value="<%=mosque.name%>">
        </div>
        <div class="field">
            <label>Image</label>
            <input type="text" name="mosque[image]" value="<%=mosque.image%>">
        </div>
        <div class="field">
            <label>Image</label>
            <input type="text" name="mosque[established]" value="<%=mosque.established%>">
        </div>
        <div class="field">
            <label>Mosque Description</label>
            <textarea name="mosque[description]"><%=mosque.description%></textarea>
        </div>
    
    
    <input type="submit" class="ui violet basic button">
</form>
</div>
<%include ./partials/footer %>

Note how we passed PUT method through method overriding.

<form class="ui form" action="/mosques/<%=mosque._id%>?_method=PUT" method="POST">

Now, let us create the put route in our app.js file.

app.put('/mosques/:id', function(req,res){
    req.body.mosque.description=req.sanitize(req.body.mosque.description);
    Mosque.findByIdAndUpdate(req.params.id, req.body.mosque, function(err, updateMosque){
        if(err){
            res.redirect('/mosques');
        } else {
            res.redirect('/mosques/'+req.params.id);
        }
    });
});

Note how we sanitize the description field.

req.body.mosque.description=req.sanitize(req.body.mosque.description);

Also, note the update command in mongoose Mosque.findByIdAndUpdate(). At the end when update is done successfully we redirect to the detailed show page again. Here are the pages in action.

figure 11-a: Edit form

figure 11-b: After submitting the form we return to show page

New Route

Let us create a form to enter a new mosque reusing the same template we used previously for edit.

new.ejs

<% include ./partials/header %>
<div class="ui main text container segment">
    <div class="ui huge header">New Mosque</div>
    <form class="ui form" action="/mosques" method="POST">
        <div class="field">
            <label>Name</label>
            <input type="text" name=mosque[name]" placeholder="name">
        </div>
        <div class="field">
            <label>Image</label>
            <input type="text" name=mosque[image]" placeholder="image">
        </div>
        <div class="field">
            <label>Established Year</label>
            <input type="text" name=mosque[established]" placeholder="Established">
        </div>
        <div class="field">
            <label>Location</label>
            <input type="text" name=mosque[location]" placeholder="location">
        </div>
        <div class="field">
            <label>Mosque Description</label>
            <textarea name=mosque[description]" placeholder="your mosque description goes here"></textarea>
        </div>
    
    
    <input type="submit" class="ui violet basic button">
</form>
</div>
<% include ./partials/footer %>

In the app.js we need to include the post route as follows.

app.post("/mosques", function(req,res){
	req.body.mosque.description=req.sanitize(eq.body.mosque.description);

	// campgrounds.push(newCamp);
	Mosque.create(req.body.mosque, function(err,mosque){
	if (err){
		console.log('smth went wrong');
	} else {
		res.redirect('/mosques');
	}
	});
});

Here is the page view.

figure 12: create a new mosque (note I entered the established year wrong, no worries I can always edit and correct

Delete a mosque

We have seen in the show.ejs file how we incorporated the delete form as a button:

<form id="delete" action="/mosques/<%=mosque._id%>?_method=DELETE" method="POST">
                    <button class="ui basic red button">Delete</button>
                </form> 

All we need is to include a delete route in our app.js as below.

app.delete('/mosques/:id', function(req,res){
    Mosque.findByIdAndRemove(req.params.id, function(err){
        if(err){
            res.redirect('/mosques');
        } else {
            res.redirect('/mosques');
        }
    })
});

Conclusion

In a later post, I have to include further enhancements like user authentication and deployment. For now I summarize the RESTful methods given in the table above but inserting another column on mongoDB methods.

URL HTTP Verb Action Mongoose Methods
/mosques/ GET index Mosque.find()
/mosques/new GET new N/A
/mosques POST create Mosque.create()
/mosques/:id GET show Mosque.findById()
/mosques/:id/edit GET edit Mosque.findById()
/mosques/:id PATCH/PUT update Mosque.findByIdAndUpdate()
/mosques/:id DELETE destroy Mosque.findByIdAndRemove()

Acknowledgment

I benefited a lot in learning NodeJS by following the Udemy Course on the subject offered by Colt Steele.