Node.js Tutorial for Beginners
In this tutorial, we examine how to get started with Node.js and how to use Express to create a few basic web pages.
Join the DZone community and get the full member experience.
Join For FreeNode.js is a fascinating technology with a quickly growing user base. Though it's often referred to as a framework, Node actually functions as a JavaScript runtime, powered by Google's V8 engine — the same engine used to power the Chrome browser. Thus, Node essentially takes the place of the browser in the execution of JavaScript code. This allows developers to use JavaScript, a language designed to be compiled and run on the client-side, on the server-side, making a full-stack JavaScript application possible. In addition to that, Node is a pretty scalable solution, as proven by its adoption by several large-scale organizations, including Netflix, Uber, PayPal, and NASA.
Introduction
To begin, let's go ahead and download Node.js onto our machines. You can find and download Node from their official website (nodejs.org). Once on the homepage, select the version you'd prefer to use. In the screenshot below, the left-hand option (8.12.0) is the latest stable release.
Your computer will take you through a few prompted pop-up windows, and then you should be good to go with Node.js. You can then open your terminal (whichever one comes on your machine) and get started with the commands we'll be going over. Also, I'll be using the Atom code editor, but feel free to use whichever one suits you best (VS Code, SublimeText, etc.).
Project Idea
I'll be basing the app I work on in this series on a project from a Udemy course (found here) that I've been using on and off for a while. I love to travel, and the US National Parks are some of my favorite places to go. To teach myself topics like Node.js, Express.js, templating engines, and Bootstrap, I'm going to design an application to keep track of my park travels. In Part 1 of this series, we're going to get some servers up and running with Node and Express.
Getting Acquainted With Node
The whole point of Node is to create an environment in which one can work with JavaScript on the backend. To that end, before getting started with creating web pages, I'd like to take a moment to explore how to work with Node in the console. To do so, let's work on setting up the server we'll use to run our future app.
Creating a server without the aid of any packages can be a bit convoluted. According to the Mozilla Developer Network, we can use the following code to set up this server:
//Load HTTP module
const http = require("http");
const hostname = '127.0.0.1';
const port = 3000;
//Create HTTP server and listen on port 3000 for requests
const server = http.createServer((req, res) => {
//Set the response HTTP header with HTTP status and Content type
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello World\n');
});
//listen for request on port 3000, and as a callback function have the port listened on logged
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
As someone new to the subject, all these constants and functions made my head spin. In the next section, I'll go over how using the Express package for Node.js makes this whole process much simpler.
Setting Up Express
One of the best, and most ubiquitous, packages for Node is Express.js, and that's what we'll be looking at for the remainder of this article.
The Express docs can be found on npm's official website, here, or Express's official website. Per the npm docs, some of the advantages of using Express are:
Robust routing.
HTTP helpers (redirection, caching, etc.).
A views system for supporting 14+ template engines.
All-in-all, it's a powerful package, good for beginners like me and seasoned developers looking to dive into Node.
First thing's first, we need to create the directory in which we'll be working. That's a simple $mkdir
command followed by the name of the directory we wish to create (I've called this file dzone_app1). Next, we need to cd
into our newly created directory and use the $touch
command to create the application that will hold our server logic; I've titled mine index.js
, though I have seen tutorials that delineate this from other files with the name server.js
.
Getting Express installed is easy. In your terminal, type the command: npm intsall express --save
. One of the great things about Node is that it comes hooked up to the official node package manager (npm for short) repository of packages. Meaning, in the command we just used, npm
is telling Node to draw from this repository and to install
the express
package. The --save
bit of the command will save Express in this application so we don't have to worry about reinstalling it later on.
Okay, now we can actually get to some coding. In the index.js file, let's use the following code to tell the application we're using Express:
const express = require("express");
const app = express();
While one can use the var
variable declarator for this as well, current documentation indicates const
is best practice.
To get the server up and running, we need to use the following code in our index.js file:
//create a server on a local host like this:
app.listen(port, function (){
console.log("Server running");
});
To this point, the code required to get a server running, and that prints a message to the console, looks like this:
const express = require("express");
const app = express();
const port = 3000;
app.listen(port, function (){
console.log("Server running");
});
6 lines of code; way simpler than the way we set up a server in the previous section.
Making Things Happen
Alright, now let's make something happen on a page! Let's head back into the index.js file and type in the following code:
app.get("/", function(req,res){
res.send("Hello World!");
});
Restart the server and go to its landing page. Once it's loaded, we'll see the message, "Hello World!"
Sweet, it works! But, just to make sure we've got it down, let's try to create another page at the address, /parks
. Head back into the index.js file and add in the following code:
app.get("/parks", function(req,res){
res.send("The Parks You've Seen");
});
Woo! After restarting the server and navigating to the /parks
page, we should see the message, "The Parks You've Seen," in tiny print on the webpage.
Altogether, the code thus far looks like this:
const express = require("express");
const app = express();
const port = 3000;
app.get("/", function(req,res){
res.send("Hello World!");
});
app.get("/parks", function(req,res){
res.send("The Parks You've Seen");
});
app.listen(port, function (){
console.log("Server running");
});
Introduction to Templating Engines
Templating engines are essentially pieces of software that allow you to render markup on the web pages you create with the powerful Node/Express combination we explored. The explanation given by the Express docs, which is far better than a beginner developer like me could do, is as follows:
A template engine enables you to use static template files in your application. At runtime, the template engine replaces variables in a template file with actual values, and transforms the template into an HTML file sent to the client. This approach makes it easier to design an HTML page.
Per these same docs, web developers working with Node and Express tend to use one of three popular template engines: Pug, Mustache, and EJS. After poking around the documentation for each of these options, I ultimately decided to go with EJS as it allows me to use actual HTML to create my markup, rather than a syntactically similar, but ultimately different, style of code.
To give a quick example of these three template engines, I'll show how to create a simple list using each. (Note: the code for Pug and Mustache in this section is taken from the docs linked to above.)
Lists in Pug
Here's how we'd have to go about creating a list with Pug:
var list = ["Uno", "Dos", "Tres",
"Cuatro", "Cinco", "Seis"]
each item in list
li= item
Come render time, however, this code will act like standard HTML, and be rendered like so:
<li>Uno</li>
<li>Dos</li>
<li>Tres</li>
<li>Cuatro</li>
<li>Cinco</li>
<li>Seis</li>
Lists in Mustache
In a Mustache view file, we'd have to enter the following code:
{
"stooges": [
{ "name": "Moe" },
{ "name": "Larry" },
{ "name": "Curly" }
]
}
In the Mustache template file, we'd then enter this code:
{{#stooges}}
<b>{{name}}</b>
{{/stooges}}
The output would, just like Pug, be rendered as standard HTML:
<b>Moe</b>
<b>Larry</b>
<b>Curly</b>
In EJS, all we have to do is create a .ejs file, let's say landing.ejs, link this page in our Express code, and then type in regular old HTML. Here's an example:
app.js (Node/Express code)
const ejs = require('ejs');
app.get("/", function(req, res){
res.render("landing");
});
landing.ejs
<!---for an ordered list --->
<ol>
<li></li>
<li></li>
<li></li>
<ol>
<!---for an ordered list --->
<ul>
<li></li>
<li></li>
<li></li>
</ul>
To me, this seems much easier. But I also don't want to make it seem like Pug and Mustache aren't great options. They're widely popular and have huge open-source communities around them. No matter which of the three you go with, you'll be working with great software. EJS just makes the most sense to my (admittedly strange) mind.
Me Make Things Pretty(ish)
As promised, we’ll make the basic pages we got to render using basic Express actually look like a web page (granted, at first, it'll look like something straight outta the '90s). And that's why I'm bringing EJS into this tutorial.
To get EJS onto your machine, run the command npm i ejs --save
. Like in the section above on creating a list in EJS, we then have to tinker with the app.js file we were using to get my Node servers and Express pages up and running. In this file, we have to tell Node that we're using EJS as our templating engine. We can do this like so:
const ejs = require('ejs');
app.set ("view engine", "ejs");
Okay, now Node knows to use EJS to render the markup for our web pages. Awesome! Next, we need to create some actual EJS files. This part is pretty simple. cd into our dzone_app1 project, and create a views directory with the command $mkdir views. Within this directory, let's create our first EJS file (I've called my file landing.ejs) with the command $touch landing.ejs
.
Fantastic! Now that we've got that file going, we can punch in the following HTML:
<h2>National Park App Page </h2>
<h3>Parks I've Seen:</h3>
<p>Park Name: <input type="text" placeholder = "Yosemite, Yellowstone..."></p>
<p>Park Picture: <input type="text" placeholder="URL"></p>
<button>Add to my Memories</button>
Then, if we run our server with the node app.js command, we should see the HTML render on the page.
To get the basic skeleton of the application down, let's create one more page, which I'll denote in my app.js file as /parks. The JavaScript to create this page server-side will look like this:
app.get("/parks", function(req,res){
res.render("parks");
});
Then $touch another EJS file, parks.ejs, and label it with a basic h2 tag (more for organizational purposes than coding reasons).
<h2> The Parks I've Seen</h2>
Then we restart the server, go to the page, and end the URL address in /parks.
Connecting Our EJS Pages
This actually turned out to be the easiest aspect of the process. I went into it thinking I'd have to use some crazy backend JavaScript in my index.js file. Nope! All I had to do was wrap the button element I'd created in my landing.ejs file last time in an anchor tag, and then provide that path to my parks.ejs file as the link. The code looks this:
<h2>National Park App Page </h2>
<h3>Parks I've Seen:</h3>
<p>Park Name: <input type="text" placeholder = "Yosemite, Yellowstone..."></p>
<p>Park Picture: <input type="text" placeholder="URL"></p>
<a href="/parks"><button>Add to my Memories</button></a>
Now, if we click the button, we go from our landing.ejs page to our parks.ejs page. Easy peasy!
Getting Actual Data to Transfer
Finishing the Landing Page
To be honest, this part gave me fits. Going into it, I thought once I had the pages connect, the rest would be a breeze. Oh, how wrong I was.
First off, we need to dive back into that HTML. The HTML for this portion proved exceedingly crucial; I now believe it was the reason I couldn't get my code to work for days. To start, we need to add a name attribute to each of the input elements. The input elements should now look like this:
<input type="text" name = "parkName" placeholder = "Park Name">
<input type="text" name = "parkImage" placeholder="Image URL">
We'll use these parkName and parkImage attributes to tie this HTML to our index.js file. But more on that later. First, let's like to wrap up this HTML. The last thing we need to do to this file is wrap the button and two inputs in a form tag. Like so:
<form action="/parks" method="POST">
<p>Park Name: <input type="text" name = "parkName" placeholder = "Park Name"></p>
<p>Park Picture: <input type="text" name = "parkImage" placeholder="Image URL"></p>
<a href="/parks"><button>Add to My Memories</button></a>
</form>
In the form attribute, we have denoted that this form will be used to post data onto the /parks page we created. That's what the <form action="/parks" method="POST">
bit of the above HTML does.
Back to the JavaScript
Adding the Body-Parser Middleware
To help with formatting our data, we need to download another npm package called data-parser. Let's go ahead and get this bit of housekeeping out of the way. As I showed when I installed Express, installing npm packages via the terminal is quite easy. Just type the command $npm i data-parser and the data-parser package downloads to your machine. Next, to let our code know we'd like it to use body-parser, we create the following variable at the top of the index.js file: const bodyParser = require("body-parser");
. Then, to finish up body-parser set up, I enter the following code below my block of variables: app.use(bodyParser.urlencoded({extended: true}));
. The area of my index.js file in which I've created all my variables to tell Node which packages I'm using now looks like this:
const express = require("express");
const app = express();
const ejs = require("ejs");
const bodyParser = require("body-parser");
const http = require("http");
const port = 3000;
app.use(bodyParser.urlencoded({extended: true}));
app.set("view engine", "ejs");
Declaring a Globally Available Variable to Temporarily Store Data
Now that we have a way to parse the data, we need a place in our code where the data will be stored. Since I'm learning to code as I write this, I don't yet know how to hook up this app to a database. For now, let's just store the data we need (the name and an image URL for the parks we enter into the form created above) in a variable. It's important to note that this data will not persist, meaning once the server is shut down or restarted, all data entered into that variable is lost.
For this method of dealing with data to work, we need to make this variable globally accessible (meaning all the files in our app can get at it). To do so, let's create the variable above the first app.get function. The code looks like this:
const express = require("express");
const app = express();
const ejs = require("ejs");
const bodyParser = require("body-parser");
const http = require("http");
const port = 3000;
app.use(bodyParser.urlencoded({extended: true}));
app.set("view engine", "ejs");
const visited = []
app.get("/", function(req, res){
res.render("landing");
});
For now, let's leave visited as an empty array. Once we get all the pieces working together, we can go back and add in some data to push to the /parks pages. But, now we have a globally declared variable.
Logic for Parsing Data
The next step is to tweak the code to render the /parks page we wrote. As a reminder, that looked like this:
app.get("/parks", function(req, res){
res.render("parks")
});
The tweaked code looks like this:
app.get("/parks", function(req, res){
res.render("parks", {visited: visited})
The {visited: visited} portion we've added here tells body-parser to accept data that's in the same format as the array we labeled visited above.
Now that the /parks page has the middleware to parse the data we pass into it, we need to move from working with app.get functions and create an app.post function. This app.post will allow users to post data (right now, the name and an image of the parks they've visited) onto the /parks page.
In this POST function, we need to tell the /parks page what type of data it will be receiving from this request and add some logic to allow for new data to be created. To help the body-parser middleware and EJS pages communicate, let's add in three variables.
var name = req.body.parkName;
var image = req.body.parkImage;
var newPark = {name: name, image: image};
Here's what req.body means, per the body-parser docs:
A new body object containing the parsed data is populated on the request object after the middleware (i.e. req.body). This object will contain key-value pairs, where the value can be a string or array (when extended is false), or any type (when extended is true).
As for my newPark variable, this logic allows users to add in new parks to their page that conforms to the name and image schema we defined as part of the visited variable. With this newPark variable, we then need to write a quick bit of logic that will push data entered into the HTML form on the /landing page to appear on the /parks page. This logic looks like this:
visited.push(newPark);
Now, we just need to wrap all this code into a POST request, like so:
app.post("/parks", function(req, res){
var name = req.body.parkName;
var image = req.body.parkImage;
var newPark = {name: name, image: image};
visited.push(newPark);
res.redirect("/parks");
});
The res.redirect bit at the bottom of the function tells the page to redirect to /parks once the logic above it has been carried out.
Embedding JavaScript Into an EJS Page
The last little thing we need to do to get data to transfer between the two pages we've created is to embed a few lines of JavaScript into the parks.ejs file. For anyone familiar with vanilla JavaScript, the code will look very familiar, with just a little EJS spice.
To use JavaScript in our EJS file, we need to use one of two demarcators, depending on what that line of JS is doing. For JavaScript that will not render on the page, the line of code needs to be book ended with these symbols: <% %>. For example: <% visited.forEach(function(park){ %>
.
For lines of JavaScript that cause something to render on the DOM, the following bookends must be used: <%= %>. For example: <%=park.name %>
.
Each line of JavaScript has to have one of these two symbols around it, or it will not work.
Here's how this looks once it's put into the basic HTML of the parks.ejs file.
<h2> The Parks I've Seen</h2>
<div>
<% visited.forEach(function(park){ %>
<img style="height: 200px; width: 200px;" data-fr-src="<%= park.image %>">
<p><%=park.name %></p>
<%});%>
</div>
The above code runs a for...each loop (the function of which I denoted as park) through the visited variable I declared earlier. This for...each loop takes each image and name combination entered into the visited variable via the HTML form on the /landing page and displays them on the /parks page.
Say the user entered in Yosemite and the URL for a particularly incredible image:
They'd then get this output:
Whoo! It works! Now, we'll look at how to style our pages and make them responsive using the open-source Bootstrap framework.
Quick PSA: If you're smart, you'll do what I didn't and wait to make any CSS tweaks until after Bootstrap has been properly integrated and all our elements are responsive.
Now, let's get to coding!
Bootstrap
Bootstrap is easy to use, automatically makes our web pages responsive (meaning they'll change size to adapt to the screen their on, and still look nice), and is totally free. Backed by Twitter, it is one of the most popular open source projects in web development.
Integrating Bootstrap
I'm using the word 'integrating,' but what we're doing isn't true integration; to get our app to use Bootstrap all we need to do is pop some links into the <head> tag of our HTML. To make Bootstrap globally accessible, we need to create two new files: header.ejs and footer.ejs. To start, header.ejs will look like this:
<html>
<head>
</head>
<body>
We'll come back in a second to plug in our links, CDNs, etc. Next, we need to close our <body> and <head> tags via the footer.ejs file.
</body>
</html>
And that's the last time we'll have to think about footer.ejs!
To make our application responsive, we need to include Bootstrap's CSS CDN in our header.ejs file. This is super simple. In the HTML we wrote a few mintues ago, just plug in this link tag:
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
Now, the full header.ejs file should look like this:
<html>
<head>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
</head>
<body>
Now our home page looks like this:
And our parks page looks like this:
To make this look a little cleaner, let's go ahead and add some CSS into our header.ejs file. Here's the CSS I've used, but obviously feel free to play around with it and make it look however you want (I'm by no means a designer):
<style media="screen">
.jumbotron { /*jumbotron creates the centered background you can see in the following screenshot*/
margin-top: 50px;
margin-left: 50px;
margin-right: 50px;
text-align: center;
}
.form-control {
text-align: center;
width: 50%;
margin: 0 auto; /*this centers the inputs on landing page*/
}
.container { /*this will center the text in our jumbotron*/
text-align: center;
}
.row { /*this creates the rows of three images on the parks page*/
grid-row: inherit;
grid-template-rows: repeat(100px, 1200px);
}
.img-fluid { /*sets the height of all the images we pass in*/
height: 200px;
}
</style>
Alright, so after plugging that in between the <head></head> tags in our header.ejs file, our homescreen looks like this:
And our parks page looks like so:
These are the kind of minor changes that help make a page look polished as opposed to sloppy. I've included some notes in the above CSS to explain what our code is doing.
Now, for a final touch, I want to make the labels on the parks page look like they're handwritten, hopefully giving it more of a photo album effect. This is really easy to do. In our header.ejs file, add in a reference to Google Fonts:
.markerFont {
font-family: 'Permanent Marker', cursive;
}
That's all the styling needed in our header.ejs file. To make the font show up on our app, however, we need to add the markerFont class to the HTML of our parks.ejs file we created last time. This is super easy. All we need to do is add class="markerFont"
to the <p> tag used to label our park pictures. Our park.ejs code should look like so:
<%include partials/header.ejs%>
<a href="/"><h1 style="margin-left: 50px; color: black;">Teddy's Travels</h1></a>
<h2 style="margin-left: 50px;">The Parks I've Seen</h2>
<div class="container">
<div class="row text-center">
<% visited.forEach(function(park){ %>
<div class="col-lg-4 col-sm-6">
<img data-fr-src="<%= park.image %>" class="img-fluid" alt="Responsive image" style="width: 400px;">
<p class ="markerFont"><b><%=park.name %></b></p>
</div>
<%});%>
</div>
</div>
<%include partials/footer.ejs%>
And if we reload our parks page, we see that we now have our handwritten font under each photo:
Woohoo!
Opinions expressed by DZone contributors are their own.
Comments