WDI Darth Vader


Express.js

aka Sinatra for Node


Express: http://expressjs.com/

1. Your First Express project

If you haven't generated your first application just yet, head back to the first part of this tutorial.

We're going to build an API in Express as well as render a View (similar to Ruby's MVC pattern).

If you haven't created an app.js file, go ahead and do so.

Let's build our first API

Inside of your app.js, we're going to...

// require express and use it
var express = require('express');
var app = express();

// create some JSON to send to a user
var data = {
  "message": "It.. is... alive!",
  "description": "your very first express API call"
};

// setup a 'get' route... JS version of sinatra!
app.get('/', function(req, res){
  res.send(data);
});

// setup a 'post' route.. again, look familiar?
app.post('/', function(req, res){
  res.send({
    "message": "thanks.. you've sent me some useful data"
  });
  console.log(req);
});

app.listen(3000);
console.log("Your Express app is running...")

2. Request object (body, params, and query)

The request object (seen as req) contains body, params, and query objects.

Install body-parser: npm install body-parser --save

To parse the body (where all data is sent via $.ajax and POSTMAN), we need to include the following Node Modules:

// include the body-parser module so we can see inside of req.body
var bodyParser = require('body-parser');
app.use(bodyParser.json()); // support json encoded bodies
app.use(bodyParser.urlencoded({ extended: true })); // support encoded bodies

Now we can appropriately read data from query strings, the request body, and params. Let's modify our above API route to read from the request body.

// create an API 'post' route.. let's look at the different sets of data we can get back
app.post('/api', function(req, res){
  res.send({
    "message": "thanks, " + req.body.name + ".. you've sent me some useful data"  
  });

  // we'll log out the params, body, and query objects here for you to see what is inside
  console.log("req.params");
  console.log(req.params);
  console.log("req.body");
  console.log(req.body);
  console.log("req.query");
  console.log(req.query);

});
// create another 'post' route that accepts 'params'
// this would look like... http://localhost:3000/items/42
app.post('/api/items/:id', function(req, res) {
  console.log(req.params);
  res.send("Your item #" + req.params.id + " is not in stock :(... womp womp");
});

We can test out our post routes using an Ajax call:

Sending over data to the request.body

$.post( "/api", { name: "James"}, function( data ) {
  console.log(data);
});

Sending over data using request.params

$.post( "/api/items/42", { item: "Hitchhiker's Guide to the Galaxy"}, function( data ) {
  console.log(data);
});

3. Generating an Express project

We're going to use the Express Generator to create an application. While the Express framework is lean and lightweight compared to Ruby on Rails, there are a few application settings that you can use.

The Express Generator allows you to easily choose which CSS preprocessor you'd like to use as well as which template framework you'd like to use.

You use the Express generator in a new folder (we're going to use whichever folder you created in the first part of this walkthrough). The syntax is as follows:

express --css preprocessor_name --template

Pre-processors

Express supports two out-of-the-box pre-processors:

Usage:

express --css less
express --css stylus

Template Frameworks

Express supports the following template frameworks out of the box:

There is a node_module that supports other frameworks like Handlebars...: https://www.npmjs.com/package/consolidate

Usage:

express --css less # uses jade
express --css stylus --ejs # uses EJS
express --css stylus --hogan # uses EJS
express --css stylus --jshtml # uses EJS

Now, we need to organize our application to make sense. We're going to open the project and move some folders around as well as create some.

4. Rendering a View

We need to install and save the EJS view engine as a dependency of our project: nopm install ejs --save

Next, we'll include the ability to read files via the path:

var path = require('path');

Now, we'll tell our application to use the EJS view engine and where to look for View files:

app.set('views', path.join(__dirname, 'views'));
// use the EJS view engine
// make sure you npm install ejs --save first!
app.set('view engine', 'ejs');

Working Example

// include the path reader... we need this to read files
var path = require('path');

// view engine setup
// set to look for views inside of "/views"
app.set('views', path.join(__dirname, 'views'));
// use the EJS view engine
// make sure you npm install ejs --save first!
app.set('view engine', 'ejs');

// render an index file... (/views/index.ejs)
app.get('/', function(req, res, next) {
  res.render('index', { title: 'Stuff', message: "Hi friends. Let's send some data to Express using Ajax!" });
});

A sample EJS View /views/index.ejs

<!DOCTYPE html>
<html>
  <head>
    <title><%= title %></title>
  </head>
  <body>
    <h1><%= title %></h1>
    <p><%= message %></p>
  </body>
</html>

Now, when you browse to http://localhost:3000 you should see a welcome page!

5. EJS Overview

Template Syntax

A conditional statement:

<% if (user) { %>
  <h2><%= user.name %></h2>
<% } %>

Compiling Teplate/Using

// declare template (str: string template)
var template = ejs.compile(str, options);
template(data);
// => Rendered HTML string

ejs.render(str, data, options);
// => Rendered HTML string

Images

<%= img_tag('maid.jpg') %>

Loops

<h1><%= title %></h1>
<ul>
    <% for(var i=0; i<supplies.length; i++) { %>
        <li>
            <a href='supplies/<%= supplies[i] %>'>
                <%= supplies[i] %>
            </a>
        </li>
    <% } %>
</ul>

6. Express.js Recap/Sinatra Comparison

GET requests in Express

app.get('/api', function(request, response) {

  // stuff happens

});

Sending Data

app.get('/api', function(request, response) {

  var someData = {
    description: "I am really tired",
    message: "zzzZZZZzzzz"
  };

  response.send(someData);

});
get '/api' do
  someData = { description: "I am really tired", message: "ZzzzZZzzz"}
end

Rendering Views

app.get('/', function(request, response) {

  var someData = {
    description: "I am really tired",
    message: "zzzZZZZzzzz"
  };

  // template name, data to use with template
  response.render('nameOfMyView', someData);

});
get '/api' do
  someData = { description: "I am really tired", message: "ZzzzZZzzz"}
  erb :nameOfMyView
end

POST requests in Express

app.post('/api/givemeallyourinfo', function(request, response) {

  // request.body, request.query, request.params
  response.send({
    "status": "200",
    "message": "Thanks.. we got all your info"
  });

});
post '/api/givemeallyourinfo' do
  {
    "status": "200",
    "message": "Thanks.. we got all your info"
  }
end

POST with Params

// localhost:5000/api/people/42/james
app.post('/api/people/:id/:name', function(request, response) {

  var id = request.params.id; // :id  => 42
  var name = request.params.name; // :name  => james
  response.send("You've requested #" + id + "!");

});