P^2
About

NODE/EXPRESS CRASH COURSE

19 JANUARY 2017

CODING

Installations and Updates

Disclaimer: This installation assumes you’re using a Mac with Homebrew installed, but check out the installation guide by MIT 6.148 otherwise!

Open your terminal. If you can’t find it, ‘cmd + space’ then searching for ‘terminal’.

Node

To check if you have Node already installed:

  > node -v

It will print out the version number if Node is already installed.

To install Node:

  > brew install node

To update Node:

  > brew update
> brew upgrade node

Express and Express generator

To check if you have Express and Express generator already installed:

  > npm list -g --depth=0

You should see express and express-generator listed if they are already installed.

To install Express and Express generator:

  > npm install -g express
> npm install -g express-generator@4

To update Express and Express generator:

  > npm update -g express
> npm update -g express-generator

Nodemon (Optional)

Nodemon is optional, but it will make your life easier. When you run your application without Nodemon, you have to restart it every time you modify the source code. Nodemon monitors your change and automatically restarts it for you.

To check if you have Nodemon already installed:

  > npm list -g --depth=0

You should see nodemon listed if it is already installed.

To install Nodemon:

  > npm install -g nodemon

To update Nodemon:

  > npm update -g nodemon

Create an Application with Express

Initializing

Make sure you’re in the directory you want to save your application. For example, if we want to save it on Desktop, we’d first run ‘cd ~/Desktop’.

To initialize the application, run in your terminal:

  > express --hbs NAME_OF_YOUR_APP
> cd NAME_OF_YOUR_APP
> npm install

This creates the application directory called NAME_OF_YOUR_APP. Replace NAME_OF_YOUR_APP with the name of your choice :)

Running the application

Make sure you’re in the application directory you just created.

To run the application with Node:

  > npm start

To run the application with Nodemon:

  > nodemon start

Now, open http://localhost:3000/ with your browser to see the application running.

If you’re running the application with Node, don’t forget to restart every time you modify the source code.

Add our own Pages

Page files for our application are stored under ‘/views’. At the initialization, ‘/view’ contains ‘index.hbs’, ‘layout.hbs’, and ‘error.hbs’. The extension ‘hbs’ stands for Handlebars, but their contents are very similar to HTML files. The only big difference is that you can supply variables from the server, and the examples below will elaborate more on how to use them.

First, we’re going to remove the default ‘index.hbs’ and ‘layout.hbs’ and add our own pages to ‘/views’. Here, our example is a web application for displaying course notes, which is roughly divided into 3 pages:

Landing page

Let’s start with the landing page. Here’s the landing page (landing.hbs):

  <!DOCTYPE html>
<html>
<head>
<title>CourseRoots</title>
<link rel='stylesheet' href='/stylesheets/style.css' />
</head>
<body>
This is the landing page for CourseRoots.
</body>
</html>

This is the very first page users should see, thus located at the root of website.

What do we mean by 'located at the root'?

Website have domain names like 'www.google.com' and 'www.facebook.com'. You can access different parts of their websites by concatenating paths after their domain names. For example, you can see Mark Zuckerberg's Facebook profile at 'https://www.facebook.com/zuck', and in this case '/zuck' is the path.

Page at the root of website has the path '/', thus located at 'https://www.facebook.com/' for example. Now, this is the same page you'd see if you simply type in 'https://www.facebook.com' instead (without '/') because your browser assumes you're asking for the root.

When we're running our application locally, the domain is 'localhost:3000' so the landing page will be located at 'http://localhost:3000/'.

When we initialized the application, they provided us with a default landing page (which used to be defined in ‘index.hbs’ and ‘layout.hbs’). We will modify the code in ‘index.js’ (under ‘/routes’) so our custom landing page (‘landing.hbs’) will be displayed instead.

In ‘index.js’, you should see this snippet:

  router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});

Replace it with:

  router.get('/', function(req, res, next) {
res.render('landing');
});

The snippet tells the application to display ‘landing.hbs’ if the user requests the path ‘/’.

'http://localhost:3000/' - Before 'http://localhost:3000/' - After

Main page

We will give our main page the path ‘/home’. We’re going to make use of the variables for this page. Here’s the main page (main.hbs):

  <!DOCTYPE html>
<html>
<head>
<title>CourseRoots</title>
<link rel='stylesheet' href='/stylesheets/style.css' />
</head>
<body>
Hello {{thisUser.name}}, this is the main page for CourseRoots.
Your user ID is: {{thisUser.id}}.
</body>
</html>

Here, we’re not trying to literally display {{thisUser.name}} and {{thisUser.id}}. Rather, we want to swap them out with strings of our choice when users requests the page.

At the bottom of ‘index.js’ right BEFORE the line ‘module.exports = router’, add:

  router.get('/home', function(req, res, next) {
let userInfo = { name: "Meowy", id: "123456" };
res.render('main', { thisUser: userInfo });
});

‘http://localhost:3000/home’

Notice how {{thisUser.name}} and {{thisUser.id}} got swapped with Meowy and 123456? The second argument of ‘res.render’ told the application what to swap out the variables with.

In the code above we passed in the ‘thisUser’ object whose attributes ‘name’ and ‘id’ correspond to ‘Meowy’ and ‘123456’, but we could also pass them in individually.

  router.get('/home', function(req, res, next) {
res.render('main', { name: "Meowy", id: "123456" });
});
  ...
<body>
Hello {{name}}, this is the main page for CourseRoots.
Your user ID is: {{id}}.
</body>
...

Note page

Here’s the note page (note.hbs):

  <!DOCTYPE html>
<html>
<head>
<title>CourseRoots</title>
<link rel='stylesheet' href='/stylesheets/style.css' />
</head>
<body>
You requested the {{thisNote.subject}} note with ID: {{thisNote.id}}.
</body>
</html>

What’s the path of note page? There are multiple notes, so let’s assume they have unique IDs. Users identify which notes they are requesting by the IDs. For example, if users want the note with ID ‘123’, then they would request the path ‘/notes/123’.

At the bottom of ‘index.js’ right BEFORE the line ‘module.exports = router’, add:

  router.get('/notes/:id', function(req, res, next) {
let noteID = req.params.id;
let noteObj = { subject: "Linear Algebra", id: noteID }
res.render('note', { thisNote: noteObj });
});

‘http://localhost:3000/notes/123’

‘http://localhost:3000/notes/987’

See how the above code defines the path to be ‘/notes/:id’. This shows that ‘:id’ can vary depending on what users request. Inside the function, we can access the value of ‘:id’ by calling ‘req.params.id’.

We can use this convention with any other variable names too. For example, if we define the path to be ‘/notes/:subject’ instead, we can access the value of ‘:subject’ by calling ‘req.params.subject’.

Styling the pages

This tutorial won’t go over the basics of CSS or JavaScript. We will assume you know how to work with them and just go over where to store the files.

CSS files are stored under the directory ‘/stylesheets’ inside ‘/public’. Say you store a file called ‘my_style.css’, then you can import it in your page like this:

  <head>
...
<link rel='stylesheet' href='/stylesheets/my_style.css' />
</head>

JavaScript files are stored under the directory ‘/javascripts’ inside ‘/public’. Say you store a file called ‘my_script.js’, then you can import it in your page like this:

  <head>
...
<script src="/javascripts/my_script.js"></script>
</head>

If you want to store small images like icons, you can store them under the directory ‘/images’ inside ‘/public’. Say you store an image called ‘my_icon.png’, then you can import it in your page like this:

  <img src="/images/my_icon.png" />

Crate our own API

Let’s also create an API of our course notes, so the users can request some paths and receive lists of course notes as JSON objects.

Prepending the paths with ‘/api’

Let’s have users request paths starting with ‘/api’ whenever they want to access some part of our API. Instead of adding more paths in ‘index.js’, we will create a new route file ‘api.js’ and add to the ‘/routes’ directory.

Here’s the code for ‘api.js’:

  var express = require('express');
var router = express.Router();

var notesByDept = {
6: [
{ dept: "6", number: "6.006", title: "Algorithm", year: "2015" },
{ dept: "6", number: "6.01", title: "Intro to EECS", year: "2016" },
],
10: [
{ dept: "10", number: "10.10", title: "Intro to ChemE", year: "2014" },
{ dept: "10", number: "10.301", title: "Fluid Mechanics", year: "2016" },
],
16: [
{ dept: "16", number: "16.09", title: "Statistics and Probability", year: "2015" },
{ dept: "16", number: "16.100", title: "Aerodynamics", year: "2012" },
],
}

/* GET all notes. */
router.get('/notes', function(req, res, next) {
res.json(notesByDept);
});

/* GET notes by department. */
router.get('/notes/:dept', function(req, res, next) {
let deptID = req.params.dept;
res.json(notesByDept[deptID]);
});

Inside ‘api.js’, we have two ‘router.get’ with the paths ‘/notes’ and ‘/notes/:dept’. What they really define are the behaviors for when users request the paths ‘/api/notes’ and ‘/api/notes/:dept’.

Instead of ‘res.render’, we now have ‘res.json’ which returns a JSON object to the user rather than a page.

We also have ‘notesByDept’ which lists course notes by their department numbers. Think of this as our little database of course notes. Although storing data inside the server as a static variable is not ideal, especially if we were to store large data and/or to be able to modify the data, but this will do for now.

One last thing: We will add two lines to ‘app.js’ so the server knows about our new ‘/api’ paths.

In ‘app.js’ right under the line ‘var index = require(‘./routes/index’)’, add:

  var api = require('./routes/api');

Also under the line ‘app.use(‘/’, index)’, add:

  app.use('/api', api);

‘http://localhost:3000/notes/123’

‘http://localhost:3000/notes/987’


That’s it for this post! Just to recap, things we covered:

Some things we haven’t covered:

This post was meant to cover the very basics to get your websites up and running, and I might do a part 2 of this post to cover some of the things we left out. Stay tuned!

Enjoyed this post? If you'd like to receive email notifications for new posts, sign up here!