Express NodeJS Tutorial

Express TutorialIn this tutorial we’ll explore the Express NodeJS framework. It provides all of the capabilities of NodeJS, also makes it easy to build robust web applications quite easily using a MVC format. I’ll cover how to install on Windows, Mac and Linux. We’ll then explore building the server, routes, incorporating Handlebars, incorporating Bootstrap, ports, middleware, app.use, app.get, catching / throwing errors, handling forms, file uploads, cookies, sessions, reading / writing files and much more.

This will serve as an overview of the whole Express framework, while the next tutorial will how to incorporate a MongoDB database into an Express app. All of the code is down below.

If you like videos like this, it helps me if you tell Google with a click here [googleplusone]

The code and images are here for download

Code From the Video

expresstut.js

// We will structure here a series of possible responses
// depending on the URL requested. As we travel through
// the pipeline we will perform needed actions using middleware
// functions. If a response is valid we will display the
// correct view and if not we will handle errors.

// This is our projects entry point. If you start the
// server by typing node expresstut.js and then open the
// browser at loclhost:3000 you'll get a 404 error if
// you haven't defined any routes
// Import the express module
var express = require('express');

var app = express();

// Block the header from containing information
// about the server
app.disable('x-powered-by');

// Set up Handlebars
// Create a directory named views and then another named layouts
// in it
// Define main.handlebars as the default layout
// Create these files in the views directory and define the
// HTML in them home.handlebars, about.handlebars,
// 404.handlebars and 500.handlebars
var handlebars = require('express-handlebars').create({defaultLayout:'main'});

app.engine('handlebars', handlebars.engine);

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

// Required when using POST to parse encoded data
// npm install --save body-parser
app.use(require('body-parser').urlencoded({extended: true}));

// Formidable is required to accept file uploads
// npm install --save formidable
var formidable = require('formidable');

// Import credentials which are used for secure cookies
// Install the cookie middleware
// npm install --save cookie-parser
var credentials = require('./credentials.js');
app.use(require('cookie-parser')(credentials.cookieSecret));

// Defines the port to run on
app.set('port', process.env.PORT || 3000);

// Create a directory called public and then a directory
// named img inside of it and put your logo in there
app.use(express.static(__dirname + '/public'));

// Define some routes. app.get receives a path and a
// function and it defines our routes. The path isn't
// case sensitive and doesn't care about trailing path
// information.
// The req object represents the HTTP request and
// contains the query string, parameters, body, header
// The res object is the response Express sends
// when it receives a request
app.get('/', function(req, res){

  // Point at the home.handlebars view
  res.render('home');
});

// This is an example of middleware It receives a request
// object, response object and the next function
// As we look for the correct information to serve it executes
// and then next() says to continue down the pipeline
app.use(function(req, res, next){
  console.log('Looking for URL : ' + req.url);
  next();
});

// You can also report and throw errors
app.get('/junk', function(req, res, next){
  console.log('Tried to access /junk');
  throw new Error('/junk does\'t exist');
});

// Catches the error and logs it and then continues
// down the pipeline
app.use(function(err, req, res, next){
  console.log('Error : ' + err.message);
  next();
});

// If we want /about/contact we'd have to define it
// before this route
app.get('/about', function(req, res){
  // Point at the about.handlebars view
  // Allow for the test specified in tests-about.js
  res.render('about');
});

// Link to contact view
app.get('/contact', function(req, res){

  // CSRF tokens are generated in cookie and form data and
  // then they are verified when the user posts
  res.render('contact', { csrf: 'CSRF token here' });
});

// Sent here after the form is processed
app.get('/thankyou', function(req, res){
  res.render('thankyou');
});

// Receive the contact form data and then redirect to
// thankyou.handlebars
// contact.handlebars calls process to process the form
app.post('/process', function(req, res){
  console.log('Form : ' + req.query.form);
  console.log('CSRF token : ' + req.body._csrf);
  console.log('Email : ' + req.body.email);
  console.log('Question : ' + req.body.ques);
  res.redirect(303, '/thankyou');
});

// Open file-upload.handlebars and store the current year
// and month. When the form is submitted the year and month
// will be passed
app.get('/file-upload', function(req, res){
  var now = new Date();
  res.render('file-upload',{
    year: now.getFullYear(),
    month: now.getMonth() });
  });

// file-upload.handlebars contains the form that calls here
app.post('/file-upload/:year/:month',
  function(req, res){

    // Parse a file that was uploaded
    var form = new formidable.IncomingForm();
    form.parse(req, function(err, fields, file){
      if(err)
        return res.redirect(303, '/error');
      console.log('Received File');

      // Output file information
      console.log(file);
      res.redirect( 303, '/thankyou');
  });
});

// Demonstrate how to set a cookie
app.get('/cookie', function(req, res){

  // Set the key and value as well as expiration
  res.cookie('username', 'DerekBanas', {expire : new Date() + 9999}).send('username has the value of : DerekBanas');
});

// Show stored cookies in the console
app.get('/listcookies', function(req, res){
  console.log("Cookies : ", req.cookies);
  res.send('Look in console for cookies');
});

// Delete a cookie
app.get('/deletecookie', function(req, res){
  res.clearCookie('username');
  res.send('username Cookie Deleted');
});

// Storing session information can be done in a few ways.
// For development we can work with a memory store
// Stores the session id in a cookie and the session data
// on the server
// npm install --save express-session

var session = require('express-session');

// parseurl provides info on the url of a request object
// npm install --save parseurl
var parseurl = require('parseurl');

app.use(session({
  // Only save back to the session store if a change was made
  resave: false,

  // Doesn't store data if a session is new and hasn't been
  // modified
  saveUninitialized: true,

  // The secret string used to sign the session id cookie
  secret: credentials.cookieSecret,
}));

// This is another example of middleware.
app.use(function(req, res, next){
  var views = req.session.views;

  // If no views initialize an empty array
  if(!views){
    views = req.session.views = {};
  }

  // Get the current path
  var pathname = parseurl(req).pathname;

  // Increment the value in the array using the path as the key
  views[pathname] = (views[pathname] || 0) + 1;

  next();

});

// When this page is accessed get the correct value from
// the views array
app.get('/viewcount', function(req, res, next){
  res.send('You viewed this page ' + req.session.views['/viewcount'] + ' times ');
});

// Reading and writing to the file system
// Import the File System module : npm install --save fs
var fs = require("fs");

app.get('/readfile', function(req, res, next){

  // Read the file provided and either return the contents
  // in data or an err
  fs.readFile('./public/randomfile.txt', function (err, data) {
   if (err) {
       return console.error(err);
   }
   res.send("The File : " + data.toString());
  });

});

// This writes and then reads from a file
app.get('/writefile', function(req, res, next){

  // If the file doesn't exist it is created and then you add
  // the text provided in the 2nd parameter
  fs.writeFile('./public/randomfile2.txt',
    'More random text', function (err) {
   if (err) {
       return console.error(err);
    }
  });

    // Read the file like before
   fs.readFile('./public/randomfile2.txt', function (err, data) {
   if (err) {
       return console.error(err);
   }

   res.send("The File : " + data.toString());
  });

});

// Defines a custom 404 Page and we use app.use because
// the request didn't match a route (Must follow the routes)
app.use(function(req, res) {
  // Define the content type
  res.type('text/html');

  // The default status is 200
  res.status(404);

  // Point at the 404.handlebars view
  res.render('404');
});

// Custom 500 Page
app.use(function(err, req, res, next) {
  console.error(err.stack);
  res.status(500);

  // Point at the 500.handlebars view
  res.render('500');
});

app.listen(app.get('port'), function(){
  console.log('Express started on http://localhost:' +
    app.get('port') + '; press Ctrl-C to terminate');
});

main.handlebars

<!DOCTYPE html>
<html lang="en">
<head>

  <!-- References a Handlebars partial in views/partials/head.handlebars -->
  {{>head}}

  <title>Express Tutorial</title>
</head>

<body>

<!-- References a Handlebars partial in views/partials/bsnavbar.handlebars -->
{{>bsnavbar}}

<!-- The HTML for each view goes here -->
<div class="container">
{{{body}}}
</div>

<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
</body>
</html>

.gitignore

# Run npm init creates package.json which defines the
# entry point as expresstut.js

# Install Express by typing npm install --save express
# in the terminal

# Install the Express Handlebars package
# npm install --save express-handlebars

#ignore packages installed by npm
node_modules
*~
.DS_Store
credentials.js

# Create a Git repository with git init
# Add files with 'git add -A' in the terminal
# Commit the changes with 'git commit -m "Initial Commit"'

credentials.js

// Used to encrypt cookies. Use a random string
// Add this to .gitignore
module.exports = { cookieSecret: 'force ability health couple', };

README.md

Express Tutorial : Describe Project Here
=======

Sub-heading
-----------

### Another deeper heading

Markdown is plain text formatting designed to convert
to HTML

Paragraphs are separated
by a blank line.

Leave 2 spaces at the end of a line to do a
line break

Text attributes *italic*, **bold**,
`monospace`, ~~strikethrough~~ .

A [link](http://example.com).

Unordered list:

  * apples
  * oranges
  * pears

Numbered list:

  1. apples
  2. oranges
  3. pears

bsnavbar.handlebars

<div class="container">
  <nav class="navbar navbar-default">
  <div class="container-fluid">
    <div class="navbar-header">
      <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
        <span class="sr-only"></span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
      </button>
      <a class="pull-left" href="#"><img src="/img/NTTLogosm.png"></a>
    </div>
    <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
      <ul class="nav navbar-nav">
        <li class="active"><a href="/">Home <span class="sr-only">(current)</span></a></li>
        <li><a href="/about">About</a></li>
        <li><a href="/contact">Contact</a></li>
        <li><a href="/file-upload">File Upload</a></li>
      </ul>
    </div><!-- /.navbar-collapse -->
  </div><!-- /.container-fluid -->
</nav>
</div>

head.handlebars

<meta charset="UTF-8">
  <!-- If IE use the latest rendering engine -->
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <!-- Set the page to the width of the device and set the zoom level -->
  <meta name="viewport" content="width = device-width, initial-scale = 1">
  <link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>

The Views

------ 404.handlebars ------

<h3>404 : Not Found</h3>

------ 500.handlebars ------

<h3>500 : Server Error</h3>

------ about.handlebars ------

<div class="page-header">
<h3>About Us</h3>
</div>

------ contact.handlebars ------

<div class="page-header">
<h3>Contact Us</h3>
</div>
<div class="contactUs">
<h4>Send Us your Questions</h4>
<form class="formContactUs" role="form"
  action="/process?form=contactus" method="POST">

  <input type="hidden" name="_csrf" value="{{csrf}}">

  <div class="form-group">
    <label for="fieldEmail" class="col-sm-2 control-label">
    Email</label>
    <div class="col-sm-4">
      <input type="text" class="form-control" id="fieldEmail"
      name="email">
    </div>
  </div> <!-- End of form-group -->

  <div class="form-group">
    <label for="fieldQues" class="col-sm-2 control-label">
    Question</label>
    <div class="col-sm-4">
      <input type="text" class="form-control" id="fieldQues"
      name="ques">
    </div>
  </div> <!-- End of form-group -->

  <div class="form-group">
    <div class="col-sm-4">
      <button type="submit" class="btn btn-default">Submit</button>
    </div>
  </div> <!-- End of form-group -->

</form>

</div> <!-- End of contactUs -->

------ error.handlebars ------

<div class="page-header">
<h3>Something Went Wrong</h3>
</div>

------ file-upload.handlebars ------

<form class="form-horizontal" role="form"
enctype="multipart/form-data" method="POST"
action="/file-upload/{year}/{month}">

<div class="form-group">
<label for="fieldName" class="col-sm-2 control-label"> Name
</label>
<div class="col-sm-4">
<input type="text" class="form-control" id="fieldName"
name="name">
</div>
</div>
<div class="form-group">
<label for="fieldEmail" class="col-sm-2 control-label"> Email
</label>
<div class="col-sm-4">
<input type="email" class="form-control"
required id="fieldEmail" name="email">
</div>
</div>
<div class="form-group">
<label for="fieldPhoto" class="col-sm-2 control-label">
Image</label>
<div class="col-sm-4">

<!-- Only accept images -->
<input type="file" class="form-control" required
accept="image/*" id="fieldPhoto" name="photo">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-4">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</div>

</form>

------ home.handlebars ------

<div class="page-header">
<h3>Welcome to my Express Tutorial</h3>
</div>

------ thankyou.handlebars ------

<div class="page-header">
<h3>Thank you for your Submission</h3>
</div>

Leave a Reply

Your email address will not be published. Required fields are marked *