Chapter 7

Express Framework

Express is one of the most popular frameworks for Node development. It handles a number of common tasks for Node apps, and streamlines the development process. In this chapter you learn how to install Express and create your first Express app. You then set up routes to create the various paths your app needs.

Next you create handlers for these routes that display views using Underscore templates. By default, Express uses Jade templates, but you'll switch it to Underscore so that you don't have to learn a new template language. Finally, you handle posted form data with a special POST route. You then validate the form data, rendering messages for any errors that occur. If the form passes validation, you send an email to the server administrator. By the end of this chapter you'll be up and running with Express, and ready to build your own Node app.

Getting Started with Express

The main advantage to working with Express is that it makes development easier. Fortunately, that also means a gentle learning curve for using Express—getting set up for your first app is a piece of cake.

Installing Express

The first step to using Express is installing the module via NPM. Since you'll probably want to use Express for a number of different Node projects, it's a good idea to install it as a global module using the -g flag:

npm install express -g

If that fails, use a sudo:

sudo npm install express -g

Even though Express has a number of dependencies, the installation process should be pretty quick.

Creating an Express App

Next create a new folder for your Express app. Inside that folder, call the following command:

express --css less

This command creates a new Express app, with support for the CSS preprocessor LESS, which will be used by the app in this chapter.

You can include a number of different features when you instantiate your Express app. For example, you can include support for sessions using --sessions.

I strongly recommend using CSS preprocessing in any app you're building. I'm not going to go into too much detail about LESS in this chapter, but you can turn to Appendix A for more information about the preprocessor. Alternatively, if there's a different preprocessor you'd like to use with Express, simply call it out in this command: --css sass or --css stylus.

Before you can run the app, you need to install more dependencies using the following command:

cd . && npm install

Finally, start the app:

node app

If everything worked correctly, you should see it output Express server listening on port 3000, as shown in Figure 7-1.

9781118524404-fg0701.tif

Figure 7-1 The Express server is now running.

When you route to http://localhost:3000 you should see a welcome message like in Figure 7-2.

9781118524404-fg0702.eps

Figure 7-2 The Express server is running on localhost:3000.

Setting Up Routes

In Chapter 3 you set up routes in Backbone to map certain URLs to different states of your app. Routes work essentially the same in Express, except that they map to actual paths on the server.

Existing Routes

The best place to start learning about routes is to take a look at the routes that already exist in the Express build. Open up app.js and look for the lines:

app.get('/', routes.index);

app.get('/users', user.list);

These are two basic routes, one at the root (http://localhost:3000/) and another at http://localhost:3000/users.

The Routes Directory

Both of these basic routes tie a path to a particular callback found in the ./routes directory of your app. For example, the second route binds the http://localhost:3000/users URL to a function found in ./routes/user.js. Open up that file to see the following:

/*

* GET users listing.

*/

exports.list = function(req, res){

  res.send('respond with a resource'),

};

The route in app.js maps the /users path to user.list, which means that it looks in ./routes/user.js for the exports.list callback. In this case, the list function prints a simple message to the screen, which you can see if you route your browser to http://localhost:3000/users, as shown in Figure 7-3.

9781118524404-fg0703.eps

Figure 7-3 The user.list route is displayed in the browser.

You might remember learning about the exports object in Chapter 6. It's used to relay variables between modules in Node. In this case it relays the list function so the router can use it.

Now take a look at the first route:

app.get('/', routes.index);

This route is a little more confusing, because routes.index doesn't refer to a file called ./routes/routes.js. Rather, this route points to behavior found in ./routes/index.js.

The Render Function

In the homepage route, you may have noticed the use of the render function, which Express uses to compile views. In this case, the render function is:

res.render('index', { title: 'Express' });

The first argument is the name of the template file. This corresponds to the index.jade file in the ./views directory. By default, Express uses Jade templates, but don't worry about this too much. Later this chapter you'll switch these for Underscore templates, so that you don't have to learn a new template language. The second argument is an object of the variables you want to pass to the template.

Creating Additional Routes

Now that you know how routes work, you can create some of your own. Open up app.js and add the following routes:

app.get('/about', routes.about);

app.get('/contact', routes.contact);

Now open./routes/index.js and add behavior for these routes:

/*

* GET about page.

*/

exports.about = function(req, res){

  res.render('about', { title: 'About' });

};

/*

* GET contact page.

*/

exports.contact = function(req, res){

  res.render('contact', { title: 'Contact' });

};

Later on you'll customize these routes a bit further, but for now just leave them as is.

When you modify the app.js file, make sure to restart the Express server to propagate the changes. These new paths won't work until you do. Or you can use Supervisor, a module you were introduced to in Chapter 6: https://github.com/isaacs/node-supervisor.

Post, Put, and Delete

So far you've used only app.get() which corresponds to a basic GET request—for example, getting a page to render in the browser. But Express is designed around REST patterns, and therefore provides methods for additional request types. You can take advantage of app.post(), app.put() and app.delete() in the exact same way as app.get(), to provide routes for whatever requests your app needs. You'll see app.post() later this chapter, when you learn how to process form data.

Rendering Views

So far you've set up some routes, but if you navigate to http://localhost:3000/about or http://localhost:3000/contact, you will get a 500 error. That's because you still need to set up the views.

Enabling Underscore Templates

By default, Express comes with a baked-in template engine called Jade. Jade is a minimalist template engine created by TJ Holowaychuk (who also created Express).

Jade Templates

To get an idea of how Jade works, open up layout.jade in the views folder of your Express app's directory. You should see something like this:

doctype 5

html

  head

    title= title

    link(rel='stylesheet', href='/stylesheets/style.css')

  body

    block content

As you can see, Jade's templates are very minimalist. There are no angular brackets around tag names, and attributes are defined in parentheses.

You can also define IDs and classes in Jade using CSS-style selectors—for example:

#my-id

  p.my-class Text content

This snippet compiles as follows:

<div id="my-id">

  <p class="my-class">Text content</p>

</div>

While Jade templates are great for reducing the number of characters in a template file, they can be difficult to read, and come with a steeper learning curve than other template engines.

Underscore Templates and uinexpress

You're already comfortable using Underscore templates after reading Chapter 4, so why not use them in Express? Fortunately, there's a Node module called uinexpress, which makes it easy to enable Underscore templates in Express. First install uinexpress and Underscore via NPM:

npm install uinexpress

npm install underscore

Next open up app.js and modify the Express configuration. Add the following lines beneath the // all environments line:

app.engine('html', require('uinexpress').__express);

app.set('view engine', 'html'),

And then comment out the line for the Jade view engine:

//  app.set('view engine', 'jade'),

Finally, restart your Express server to put the changes into effect.

Converting Jade Templates

If you route to http://localhost:3000 you will see that the page is now broken. That's because the Jade templates are no longer working. But don't worry—you can easily modify the existing Jade templates to get a base state for views in your app. First, in the views directory, open up layout.jade, which should look like this:

doctype 5

html

  head

    title= title

    link(rel='stylesheet', href='/stylesheets/style.css')

  body

    block content

Now, convert this template into an Underscore version that's a bit more familiar:

<!DOCTYPE html>

<html>

<head>

    <title><%=title %></title>

    <link rel="stylesheet" href="/stylesheets/style.css" />

</head>

<body>

<%=body %>

</body>

</html>

Here you see some familiar Underscore patterns, such as variables delimited by <% %>. Save this new Underscore template as layout.html.

Next, open up index.jade, which should look like this:

extends layout

block content

  h1= title

  p Welcome to #{title}

You can also convert this into an Underscore template:

<h1><%=title %></h1>

<p>Welcome to <%=title %></p>

Save this new file as index.html, and you're done. Reload the page on http://localhost:3000, and you should see the same welcome message as before.

You may have noticed that the extends layout and block content calls were removed from these templates. But don't worry, the new Underscore templates function exactly like their Jade predecessors.

When the index view is rendered, it compiles the content in index.html and passes that to the <%=body %> variable in layout.html.

One of the best parts of working with Node is that you can reuse the same template files on the client-side. That means you can create a static version of the page using Node, and also load the exact same page using Ajax.

In Chapter 3, you read about loading Backbone views with pushState. There I explained why it was important to have a static backup for each page. There's no easier way to accomplish that than using a Node server that leverages the exact same Underscore templates on the frontend.

Creating Views

Once you've enabled Underscore templates, you can start building views for the various pages. I'm going to keep these views really simple, but feel free to embellish them with your Underscore skills.

The Homepage

First, start with the template for the homepage. In the ./views directory add the following to index.html:

<h1><%=title %></h1>

<% if ( typeof subtitle !== 'undefined' ) { %>

<h2><%=subtitle %></h2>

<% } %>

<p><%=description %></p>

Here a few new variables have been added to the function: an optional subtitle and a description.

Now open up index.js in the ./routes directory. The route for the homepage is already pointing to this template; you just have to change the variables that are passed into it:

/*

* GET home page.

*/

exports.index = function(req, res){

  res.render('index', {

    title: 'My First Express App',

    description: 'This is my first Express app, so go easy on me'

  });

};

Now, if you reload the page at http://localhost:3000, you'll see the new homepage as shown in Figure 7-4.

9781118524404-fg0704.eps

Figure 7-4 The new homepage view is rendering correctly.

The About Page

Next you need to create a view for the about page. However, the template for the about page is going to look pretty much like the one for the homepage. There's no sense in duplicating the homepage template, when all you need to do is reference the existing template and pass in new variables. That said, it also doesn't make much sense to continue calling it the index.html template. Rename the template to main.html, and modify the route for the homepage:

/*

* GET home page.

*/

exports.index = function(req, res){

  res.render('main', {

    title: 'My First Express App',

    description: 'This is my first Express app, so go easy on me'

  });

};

Then, set up the view in the about page route:

/*

* GET about page.

*/

exports.about = function(req, res){

  res.render('main', {

    title: 'About',

    subtitle: 'All about my Express app',

    description: 'I built this app using Node and the Express framework'

  });

};

As you can see, this time the template is using the optional subtitle variable.

Finally, make sure to restart your Express server, to empty the cache from the previous templates. Now when you route to http://localhost:3000/about, you see the new content, as shown in Figure 7-5.

9781118524404-fg0705.eps

Figure 7-5 The about page view is rendering properly.

The Contact Page

Last but not least, you need to set up a view for the contact page. This view will be a little different, so you need to create a new template. Create a file named contact.html in the ./views directory and add the following markup:

<h1><%=title %></h1>

<p><%=description %></p>

<form method="post">

  <div class="form-item">

    <label for="name">Name:</label>

    <input type="text" name="name" id="name" required />

  </div>

  

  <div class="form-item">

    <label for="email">Email:</label>

    <input type="email" name="email" id="email" required />

  </div>

  

  <div class="form-item">

    <label for="message">Message:</label>

    <textarea name="message" id="message" required></textarea>

  </div>

  

  <div class="form-item">

    <input type="submit" value="Send" />

  </div>

</form>

Next, adjust the route handler:

/*

* GET contact page.

*/

exports.contact = function(req, res){

  res.render('contact', {

    title: 'Contact Us',

    description: 'Send us a message and we'll get back to you'

  });

};

Now, if you route to http://localhost:3000/contact, you'll see that the page is looking pretty ugly. It's time to add some basic CSS to improve the styling. Go to the ./public/stylesheets directory and open up style.less. In here, add the following LESS styling:

.form-item {

  @labelWidth: 100px;

  @formPadding: 5px;

  

  padding: 5px 0;

  

  label {

    display: inline-block;

    width: @labelWidth - 10px;

    padding-right: 10px;

    text-align: right;

    vertical-align: top;

  }

  

  input[type=text], input[type=email] {

    width: 250px;

    padding: @formPadding;

  }

  

  textarea {

    width: 400px;

    height: 150px;

    padding: @formPadding;

  }

  

  input[type=submit] {

    margin-left: @labelWidth;

    font-size: 36px;

  }

}

When you save style.less, Express automatically compiles it to style.css. Now, navigate to http://localhost:3000/contact and you will see the rendered form, as in Figure 7-6.

9781118524404-fg0706.eps

Figure 7-6 The contact view is being rendered nicely with the additional styling.

LESS styling looks pretty much like regular CSS, with a few extra things mixed in, such as the @labelWidth and @formPadding variables.

Additionally, notice how the styles are all nested under .form-item, which makes for better stylesheet organization, but don't worry, it still compiles to regular CSS. For example, the nested label becomes .form-item label.

Read Appendix A to learn more about LESS and CSS preprocessing.

The Layout Template

When creating the templates for these different views, don't forget about layout.html. You can use this template to add anything you want to exist on every page of your app—for instance, a Google Analytics tracking code, or footer for the site.

For example, you've already set up routes for different pages of the app, but how are users supposed to get to those pages? Better add some navigation to layout.html:

<!DOCTYPE html>

<html>

<head>

  <title><%=title %></title>

  <link rel="stylesheet" href="/stylesheets/style.css" />

</head>

<body>

<nav>

  <ul>

    <li>

    <a href="/">Home</a>

    </li>

    

    <li>

    <a href="/about">About</a>

    </li>

    

    <li>

    <a href="/contact">Contact</a>

    </li>

  </ul>

</nav>

<%=body %>

</body>

</html>

Next add some more styling to style.less:

nav {

  background-color: tomato;

  padding: 0 50px;

  position: absolute;

  top: 0;

  left: 0;

  right: 0;

  

  > ul {

    list-style: none;

    margin: 0;

    padding: 0;

  }

  

  li {

    > a {

      color: papayawhip;

      text-decoration: none;

      float: left;

      padding: 20px;

      

      &:hover {

        color: tomato;

        background-color: papayawhip;

      }

    }

  }

}

Now that the navigation has been added, the page is looking a lot nicer, as shown in Figure 7-7.

9781118524404-fg0707.eps

Figure 7-7 Navigation has been added to layout.html, which adds it to all the views in the app.

Don't worry too much about the LESS code—Express will compile it automatically to regular CSS, and if you want to learn more about LESS, read Appendix A.

Handling Form Data

At this point, a few basic routes and views are set up in the Express app, but you still need to handle the form data. In this section, you first learn how to set up post routes to handle the post data from the form. Then you validate the form data on the server side, rendering any validation errors on the client.

Creating a Post Route

Just for fun, try submitting the contact form as it currently stands. You should see an error Cannot POST /contact, as shown in Figure 7-8.

That might seem a bit strange, since you already set up a route for /contact. However, you still can't post form data to that route, because it's set up as a GET route:

app.get('/contact', routes.contact);

To process a POST request, you'll need to set up a different POST route in app.js:

app.post('/contact', routes.contactPostHandler);

9781118524404-fg0708.eps

Figure 7-8 Posting the form triggers an error.

Now, add the handler in ./routes/index.js:

/*

* POST contact page.

*/

exports.contactPostHandler = function(req, res){

  console.log('Name: ' + req.body.name);

  console.log('Email: ' + req.body.email);

  console.log('Message: ' + req.body.message);

  

  res.send('Form posted successfully'),

};

Although this handler is very basic, there are a few important patterns to note. Mainly, notice how the script drills into the request object req to pull the different fields that were posted. For example req.body.name pulls the data that was posted in the <input type=”text” name=”name” /> field.

Restart your Express server, and submit the form. You should see the completion message displayed in the browser. Additionally, the form data is output in the Node console like in Figure 7-9.

9781118524404-fg0709.tif

Figure 7-9 The form data is being output in the console.

Sending Feedback to the Template

The form is already outputting a basic success message, but that still leaves a lot of room for improvement. If there are any errors with the form, those should be output to the user, to provide an opportunity to resubmit the form.

Validation

The form markup already includes HTML5 form validation hooks, such as the email field and required attribute. Assuming the user has an HTML5 compliant browser, these fields will be validated before the form is ever posted to your Express server.

However, it's important to remember that some malformed data might get through despite these checks. For example, the validation won't work if the user has an older browser, or in the unlikely event that a hacker tries to post directly into the form. Fortunately, you can build additional validation into the backend to sanitize the form data, and send meaningful responses to the user. First, build validation to make sure all the required fields are filled in:

// validate required fields

function isFilled(field) {

  return field !== undefined && field !== '';

}

exports.contactPostHandler = function(req, res) {

  var response = 'Form posted successfully',

      required = [ 'name', 'email', 'message' ],

      missing = [];

  

  // check required fields

  missing = required.filter(function(prop) {

    return !isFilled(req.body[prop]);

  });

  if ( missing.length ) {

    response = 'Please fill out all required fields (' + missing.join(', ') +

')';

  }

  // send the success or error message

  res.send( response );

};

There are a couple things going on here:

• The script defines an isFilled() function, which checks to make sure the fields aren't empty or undefined. It's important to do both checks, in case someone posts directly into the form.

• The items in the required array are filtered against the isFilled() test. If any are missing, an appropriate error message is created.

• If errors exist, the error is printed to the screen, otherwise the success message is printed.

This is a pretty basic form, so the only other thing you have to validate is the email address. You can do so using a simple email regex:

// validate required fields

function isFilled(field) {

  return field !== undefined && field !== '';

}

  

// validate email address

var emailRegex = /^(([^<>()[]\.,;:s@"]+(.[^<>()[]\.,;:s@"]+)*)|

(".+"))@(([[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}])|

(([a-zA-Z-0-9]+.)+[a-zA-Z]{2,}))$/;

function isValidEmail(email) {

  return emailRegex.test(email);

}

exports.contactPostHandler = function(req, res) {

  var response = 'Form posted successfully',

      required = [ 'name', 'email', 'message' ],

      missing = [];

  

  // check required fields

  missing = required.filter(function(prop) {

    return !isFilled(req.body[prop]);

  });

  if ( missing.length ) {

    response = 'Please fill out all required fields (' + missing.join(', ') +

')';

  }

  

  // check email

  else if ( !isValidEmail( req.body.email ) ) {

    response = 'Please enter a valid email address';

  }

  

  // send the success or error message

  res.send( response );

};

The email test is fairly straightforward. Look at the bolded parts of the script to see an isValidEmail function, which uses a basic regular expression to validate the email address.

The validation for this form is pretty simple. But if you're working on a more intense form, consider using the Node Validator module: https://github.com/chriso/node-validator.

Rendering Feedback in the Template

So far the script just prints a basic error or success message when the form is submitted. But it would be much better to output that feedback in the template. Not only will it look better, but it will also give the user the opportunity to correct any issues with the form. Open up contact.html in the ./views directory, and make the following changes:

<h1><%=title %></h1>

<% // error message

if (typeof success != 'undefined' && !success) { %>

<p style="color: red"><%=description %></p>

<% }

else { %>

<p><%=description %></p>

<% } %>

<% // only output the form if not posted, or unsuccessful

if (typeof success == 'undefined' || !success) { %>

<form method="post">

  <div class="form-item">

    <label for="name">Name:</label>

    <input type="text" name="name" id="name" required <%= typeof name !=

'undefined' ? 'value="' + name + '"' : '' %>/>

  </div>

  

  <div class="form-item">

    <label for="email">Email:</label>

    <input type="email" name="email" id="email" required

<%= typeof email != 'undefined' ? 'value="' + email + '"' : '' %>/>

  </div>

  

  <div class="form-item">

    <label for="message">Message:</label>

    <textarea name="message" id="message" required><%= typeof message !=

'undefined' ? message : '' %></textarea>

  </div>

  

  <div class="form-item">

    <input type="submit" value="Send" />

  </div>

</form>

<% } %>

Here a few basic changes, which are highlighted in bold, have been made to the template:

• Error styling has been added if the form is posted unsuccessfully.

• The form is set to only render when the posting is unsuccessful (or hasn't been posted at all).

• The value for each field is being added if it exists. That way the user won't lose anything he or she has entered into the form when there is an error.

The changes here are all straightforward, but pay attention to the typeof checks. Underscore templates throw errors if you try to reference a variable that doesn't exist, so it's important to check for undefined variables.

Passing New Variables to the Template

Finally, modify the view controller to pass the appropriate variables to the template when the form is submitted:

// validate required fields

function isFilled(field) {

  return field !== undefined && field !== '';

}

  

// validate email address

var emailRegex = /^(([^<>()[]\.,;:s@"]+(.[^<>()[]\.,;:s@"]+)*)|

(".+"))@(([[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}])|

(([a-zA-Z-0-9]+.)+[a-zA-Z]{2,}))$/;

function isValidEmail(email) {

  return emailRegex.test(email);

}

exports.contactPostHandler = function(req, res) {

  var response = 'Thank you for contacting us, we will get

back to you as soon as possible',

      required = [ 'name', 'email', 'message' ],

      missing = [],

      success = false;

  

  // check required fields

  missing = required.filter(function(prop) {

    return !isFilled(req.body[prop]);

  });

  if ( missing.length ) {

    response = 'Please fill out all required fields (' + missing.join(', ') + ')';

  }

  

  // check email

  else if ( !isValidEmail( req.body.email ) ) {

    response = 'Please enter a valid email address';

  }

  else {

    success = true;

  }

    

  // build the template variables

  var templateVars = {

    description: response,

    success: success

  };

  // error output

  if ( !success ) {

    console.log( response );

    

    templateVars.title = 'Contact Us';

    templateVars.name = req.body.name;

    templateVars.email = req.body.email;

    templateVars.message = req.body.message;

  }

  

  // else success output

  else {

    templateVars.title = 'Form posted successfully';

  }

  

  // render the view

  res.render('contact', templateVars);

};

The changes in the script are highlighted in bold:

• A success flag has been added—it's initially false, then set to true if there are no errors. This controls the styling of the message in the template.

• The script begins building the universal template variables for all cases.

• On error, the script adds extra template variables including posted field values, so that they can be passed back into the form.

• On success, it adds a different title for the success page (the description variable has already been set with the response variable).

• The view is rendered with the new template variables.

As you can see in Figure 7-10, the contact form is now being rerendered with the form error.

The error message here is pretty basic. But if you want to, you can build in inline validation messages, or any other kind of feedback your form needs.

9781118524404-fg0710.eps

Figure 7-10 The form displays an error message when the user tries to submit it without an email address.

Sending an Email

Finally, you're going to want to do something with the data that's submitted to this contact form. You could simply log it to a file on the server, and check that every so often. But it's a better idea to send it to yourself in an email—after all, this is a contact form.

There are a few modules out there for sending emails from a Node server, but the easiest to use is EmailJS. First, install EmailJS with NPM:

npm install emailjs

Now you can use the module to send the contact form data to your email address.

Connecting to an SMTP Server

The EmailJS module doesn't create its own SMTP server. Instead, you need to connect to an existing one, like Gmail. First include the module and then connect to your SMTP server (all of the code in this section should be in the success portion of your form handler):

// connect to your smtp server

var emailjs = require('emailjs'),

var server = emailjs.server.connect({

  user: 'username',

  password: 'password',

  host: 'smtp.gmail.com',

  ssl: true

});

Here EmailJS connects securely to the SMTP server you specify. Make sure to fill in your username and password, as well as the host if you want to use something other than Gmail.

You can also build your own SMTP server in Node. Check out the SimpleSMTP module: https://github.com/andris9/simplesmtp.

Building the Email Message

Next, build a message using the form data:

// build the email body with a datestamp

var emailBody = 'From: ' + req.body.name + ' <' + req.body.email + '>' +

" ";

emailBody += 'Message: ' + req.body.message + " ";

emailBody += 'Sent automatically from Node server on ' + Date();

Here, the script builds the body of the email using the name, email, and message that are entered into the form. It also adds a datestamp. I kept this example simple, but feel free to use a template for the email message if you'd prefer.

Sending the Email

Finally, send the email using EmailJS:

// send the email to the server admin

server.send({

  from:    'Node Server <no-reply@localhost>',

  to:      'Server Admin <admin@localhost>',

  subject: 'Contact form submission',

  text: emailBody

}, function(err, message) {

  console.log(err || message);

});

Here, the script sends the email you built to the server administrator. Make sure to change the to and from addresses.

Gmail prevents you from spoofing another email address, so you can't set the from address to the email address entered into the form. But if you're using another SMTP server, you might consider sending it from the user's email address, so you can respond directly to them.

For more information about EmailJS, visit https://github.com/eleith/emailjs. Alternatively, if you need more robust email support, check out Node Email Templates: https://github.com/niftylettuce/node-email-templates.

Wrapping Up

Finally, on the off-chance the email fails, it's a good idea to relay that to the user. To do so, you can print a basic error message in the EmailJS callback. However, since the callback is asynchronous, it won't actually display to the user because the success message will have already printed on the screen. Thus, the script has to be reworked a bit:

// validate required fields

function isFilled(field) {

  return field !== undefined && field !== '';

}

  

// validate email address

var emailRegex = /^(([^<>()[]\.,;:s@"]+(.[^<>()[]\.,;:s@"]+)*)|(".+"))@(([[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}])|(([a-zA-Z-0-9]+.)+[a-zA-Z]{2,}))$/;

function isValidEmail(email) {

  return emailRegex.test(email);

}

exports.contactPostHandler = function(req, res) {

  var response = 'Thank you for contacting us, we will get back to you as soon as possible',

      required = [ 'name', 'email', 'message' ],

      missing = [],

      success = false;

  

  // check required fields

  missing = required.filter(function(prop) {

    return !isFilled(req.body[prop]);

  });

  if ( missing.length ) {

    response = 'Please fill out all required fields (' + missing.join(', ') + ')';

  }

  

  // check email

  else if ( !isValidEmail( req.body.email ) ) {

    response = 'Please enter a valid email address';

  }

  else {

    success = true;

  }

    

  // build the template variables

  var templateVars = {

    description: response,

    success: success

  };

  // error output

  if ( !success ) {

    console.log( response );

    

    templateVars.title = 'Contact Us';

    templateVars.name = req.body.name;

    templateVars.email = req.body.email;

    templateVars.message = req.body.message;

    

    // render the template

    res.render('contact', templateVars);

  }

  

  // else success output

  else {    

    // connect to your smtp server

    var emailjs = require('emailjs'),

    var server = emailjs.server.connect({

      user: 'username',

      password: 'password',

      host: 'smtp.gmail.com',

      ssl: true

    });

    

    // build the email body with a datestamp

    var emailBody = 'From: ' + req.body.name + ' <' + req.body.email + '>' +

     " ";

    emailBody += 'Message: ' + req.body.message + " ";

    emailBody += 'Sent automatically from Node server on ' + Date();

    

    // send the email to the server admin

    server.send({

      from:    'Node Server <no-reply@localhost>',

      to:      'Server Admin <admin@localhost>',

      subject: 'Contact form submission',

      text: emailBody

    }, function(err, message) {

      console.log(err || message);

      

      // if smtp error

      if ( err ) {

        res.send('Sorry, there was an error sending your message, please try again later'),

      }

      // otherwise show success message

      else {

        templateVars.title = 'Message sent successfully'

        

        // render the template

        res.render('contact', templateVars);

      }

    });

  }

};

Here a few basic changes have been made:

• The render function is pulled into the error handler to render any validation errors.

• If the SMTP emailer fails, a basic error is simply printed to the screen. It's a good idea not to rerender the form in this case, since the user will most likely not be able to use it.

• If the SMTP emailer is successful, the success message is displayed from within the callback. This way the success message won't overwrite the error message.

Summary

In this chapter you learned the basics of the Express framework. You learned how to install Express and start an Express server. You then learned how to set up routes to define the paths for your app.

Next you set up controllers on those routes to render views using Underscore templates. Then, you learned how to create a POST route to handle form data from your app. You validated the data, and displayed error messages when they occurred. On successful form submission, the server sent an email to the admin. To do so, it used the EmailJS module to connect to an external SMTP server.

You now have a pretty firm foundation in Node development. In the next chapter, you learn how to use a NoSQL database called MongoDB. This will support the data component of your Node app. Then in Chapter 9 you learn how to create even faster I/O communication with the client-side using WebSockets, and tie everything together to build a real-time app.

Additional Resources

Express Documentation: http://expressjs.com/api.html

Tutorials

Getting Started with Express: http://howtonode.org/getting-started-with-express

Express.js Tutorial: http://www.hacksparrow.com/express-js-tutorial.html

Template Resources

uinexpress Documentation: https://github.com/haraldrudell/uinexpress

Underscore Template Documentation: http://underscorejs.org/#template

Jade Documentation: https://github.com/visionmedia/jade#readme

Form Resources

Node Form Validation Module: https://github.com/chriso/node-validator

Email Resources

EmailJS Documentation: https://github.com/eleith/emailjs

Node Email Templates: https://github.com/niftylettuce/node-email-templates

Node SMTP Server: https://github.com/andris9/simplesmtp

Other Notable Frameworks

Geddy: http://geddyjs.org/

Ember: http://emberjs.com/

Flatiron: http://flatironjs.org/

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset