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:
It will print out the version number if Node is already installed.
To install Node:
To update Node:
Express and Express generator
To check if you have Express and Express generator already installed:
You should see express and express-generator listed if they are already installed.
To install Express and Express generator:
To update Express and 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:
You should see nodemon listed if it is already installed.
To install Nodemon:
To update 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:
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:
To run the application with Nodemon:
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.hbs': Landing page for introducing our web application.
- 'main.hbs': Main page for displaying a list of notes when the user is logged in.
- 'note.hbs': Note page for displaying an individual note.
Landing page
Let’s start with the landing page. Here’s the landing page (landing.hbs):
This is the very first page users should see, thus located at the root of website.
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:
Replace it with:
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):
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:
‘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.
Note page
Here’s the note page (note.hbs):
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:
‘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:
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:
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:
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’:
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:
Also under the line ‘app.use(‘/’, index)’, add:
‘http://localhost:3000/notes/123’
‘http://localhost:3000/notes/987’
That’s it for this post! Just to recap, things we covered:
- Setting up the environment
- Creating and running an Express application
- Adding new pages and files
- Using 'router.get' to handle GET requests (e.g. displaying pages, returning JSON objects)
Some things we haven’t covered:
- Using 'router.post' to handle POST requests (e.g. accepting form submissions)
- Connecting databases
- Logging users in
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!