Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 17

A Simple Web Server with Node:

var http = require('http');


http.createServer(function(req,res){
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello world!');
}).listen(3000);
console.log('Server started on localhost:3000; press Ctrl-C
to terminate....');

Routing
Routing refers to the mechanism for serving the client the content it has
asked for.

var http = require('http');


http.createServer(function(req,res){
// normalize url by removing querystring, optional
// trailing slash, and making it lowercase
var path = req.url.replace(/\/?(?:\?.*)?$/, '').toLowerCase();
switch(path) {
case '':
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Homepage');
break;
case '/about':
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('About');
break;
default:
res.writeHead(404, { 'Content-Type': 'text/plain' });
res.end('Not Found');
break;
}
}).listen(3000);
console.log('Server started on localhost:3000; press Ctrl-C to
terminate....');
Serving Static Resources
Now that we’ve got some simple routing working, let’s serve some real
HTML and a logo image. These are called “static resources” because they
don’t change If you’ve worked with Apache or IIS, you’re probably used to
just creating an HTML file, navigating to it, and having it delivered to the
browser automatically. Node doesn’t work like that: we’re going to have
to do the work of opening the file, reading it, and then sending its
contents along to the browser. So let’s create a directory in our project
called public (why we don’t call it static will become evident in the next
chapter). In that directory, we’ll create home.html, about.html,
notfound.html, a subdirectory called img, and an image called
img/logo.jpg

var http = require('http'),


fs = require('fs');
function serveStaticFile(res, path, contentType,
responseCode) {
if(!responseCode) responseCode = 200;
fs.readFile(__dirname + path, function(err,data) {
if(err) {
res.writeHead(500, { 'Content-Type': 'text/plain' });
res.end('500 - Internal Error');
} else {
res.writeHead(responseCode,
{ 'Content-Type': contentType });
res.end(data);
}
});
}

http.createServer(function(req,res){
// normalize url by removing querystring, optional
// trailing slash, and making lowercase
var path = req.url.replace(/\/?(?:\?.*)?$/, '') .toLowerCase();
switch(path) {
case '':
serveStaticFile(res, '/public/home.html', 'text/html');
break;
case '/about':
serveStaticFile(res, '/public/about.html', 'text/html');
break;
case '/img/logo.jpg':
serveStaticFile(res, '/public/img/logo.jpg', 'image/jpeg');

break;
default:
serveStaticFile(res, '/public/404.html', 'text/html',
404);
break;
}
}).listen(3000);
console.log('Server started on localhost:3000; press Ctrl-C to
terminate....');

Express: Web Frame work

USING Express we will create The Meadowlark


Travel Website a company offering services for
people visiting the great state of Oregon.

Initial Steps :
Start by creating a new directory for your project: this will be
the root directory for your project.
npm manages project dependencies—as well as metadata
about the project—in a file called package.json. The easiest
way to create this file is to run npm init: it will ask you a series
of questions and generate a package.json file to get you started
(for the “entry point” question, use meadowlark.js or the name
of your project).
Create a project directory called website
E:\nodeapps>md website

E:\nodeapps>cd website

E:\nodeapps\website>npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess
sensible defaults.
See `npm help json` for definitive documentation on these
fields and exactly what they do.
Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.
Press ^C at any time to quit.
package name: (website)
version: (1.0.0)
description:
entry point: (index.js) app.js
test command:
git repository:
keywords:
author:
license: (ISC)
About to write to E:\nodeapps\website\package.json:
{
"name": "website",
"version": "1.0.0",
"description": "",
"main": "app.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
Is this OK? (yes) yes

The first step will be installing Express. Run the following npm
command:
npm install --save express
Running npm install will install the named package(s) in the
node_modules directory. If you specify the --save flag, it will
update the package.json file. Since the node_modules dirctory
can be regenerated at any time with npm, we will not save it in
our repository. To ensure we don’t accidentally add it to our
repository, we create a file called .gitignore: # ignore packages
installed by npm
node_modules # put any other files you don't want to check in
here, # such as .DS_Store (OSX), *.bak, etc.
Now create a file called app.js. This will be our project’s entry
point

app.js // it will create a web server along with routes


var express = require('express');
var app = express();
app.set('port', process.env.PORT || 3000);
// custom 404 page
app.use(function(req, res){
res.type('text/plain');
res.status(404);
res.send('404 - Not Found');
});
// custom 500 page
app.use(function(err, req, res, next){
console.error(err.stack);
res.type('text/plain');
res.status(500);
res.send('500 - Server Error');
});
app.listen(app.get('port'), function(){
console.log( 'Express started on http://localhost:' +
app.get('port') + '; press Ctrl-C to terminate.' );
});

Now we can start the server


Open terminal and type
node app.js

Let’s add some routes for the home page and an


about page. Before the 404 handler, we’ll add two
new routes:
app.get('/', function(req, res){
res.type('text/plain');
res.send('Meadowlark Travel');
});
app.get('/about', function(req, res){
res.type('text/plain');
res.send('About Meadowlark Travel');
});
app.get is the method by which we’re adding routes. In the
Express documentation, you will see app.VERB. This doesn’t
mean that there’s literally a method called VERB; it’s just a
placeholder for your (lowercased) HTTP verbs (“get” and “post”
being the most common). This method takes two parameters:
a path and a function. The path is what defines the route. Note
that app.VERB does the heavy lifting for you: by default, it
doesn’t care about the case or trailing slash, and it doesn’t
consider the querystring when performing the match. So the
route for the About page will work for /about, /About, /about/,
/about?foo=bar, /about/?foo=bar, etc.
The function you provide will get invoked when the route is
matched. The parameters passed to that function are the
request and response objects,

Views and Layouts


a view is what gets delivered to the user. In the case of a
website, that usually means HTML, though you could also
deliver a PNG or a PDF, or anything that can be rendered by
the client. For our purposes, we will consider views to be HTML.
Where a view differs from a static resource (like an image or
CSS file) is that a view doesn’t necessarily have to be static:
the HTML can be constructed on the fly to provide a customized
page for each request.

Express supports many different view engines that provide


different levels of abstraction.
Handlebars (which is based on the popular language-
independent templating
language Mustache) doesn’t attempt to abstract away HTML for
you: you write HTML with special tags that allow Handlebars to
inject content.
To provide Handlebars support, we’ll use Eric Ferraiuolo’s
express3-handlebars
package (despite the name, this package works fine with
Express 4.0). In your project directory, execute:
npm install --save express3-
handlebars
Then in app.js , add the following lines after the app has been
created:
var app = express();
// set up handlebars view engine
var handlebars = require('express3-handlebars')
.create({ defaultLayout:'main' });
app.engine('handlebars', handlebars.engine);
app.set('view engine', 'handlebars');

This creates a view engine and configures Express to use it by


default. Now create a directory called views that has a
subdirectory called layouts.
When you build a website, there’s a certain amount
of HTML that’s the same—or very close to the
same—on every page. Not only does it become
tedious to rewrite all that repetitive code for every
page, it creates a potential maintenance
nightmare: if you want to change something on
every page, you have to
change all the files. Layouts free you from this,
providing a common framework for all the pages
on your site.
So let’s create a template for our site. Create a file
called views/layouts/main.handlebars:
<!doctype html>
<html>
<head>
<title>Meadowlark Travel</title>
</head>
<body>
{{{body}}}
</body>
</html>

The only thing that you probably haven’t seen


before is this: {{{body}}}. This expression will be
replaced with the HTML for each view. When we
created the Handlebars instance, note we specified
the default layout (defaultLayout:'main'). That
means that unless you specify otherwise, this is
the layout that will be used for any view.
Now let’s create view pages for our home page,
views/home.handlebars:
<h1>Welcome to Meadowlark Travel</h1>
Then our About page, views/about.handlebars:
<h1>About Meadowlark Travel</h1>
Then our Not Found page, views/404.handlebars:
<h1>404 - Not Found</h1>
And finally our Server Error page,
views/500.handlebars:
<h1>500 - Server Error</h1>

Now that we’ve got some views set up, we have to replace our old routes with new
routes

that use these views:

app.get('/', function(req, res) {

res.render('home');
});

app.get('/about', function(req, res) {

res.render('about');

});

// 404 catch-all handler (middleware)

app.use(function(req, res, next){

res.status(404);

res.render('404');

});

// 500 error handler (middleware)

app.use(function(err, req, res, next){

console.error(err.stack);

res.status(500);

res.render('500');

});

Note that we no longer have to specify the content type or status code: the view engine

will return a content type of text/html and a status code of 200 by default. In the catch

all handler, which provides our custom 404 page, and the 500 handler, we have to set

the status code explicitly.

Static Files and Views


Express relies on a middleware to handle static files and views
The static middleware allows you to designate one or more
directories as containing static resources that are simply to be
delivered to the client without any special handling. This is
where you would put things like images, CSS files, and client-
side JavaScript files. In your project directory, create a
subdirectory called public (we call it public because anything
in this directory will be served to the client without question).
Then, before you declare any routes, you’ll add the static
middleware:
app.use(express.static(__dirname +
'/public'));
The static middleware has the same effect as creating a route
for each static file you
want to deliver that renders a file and returns it to the client. So
let’s create an img
subdirectory inside public, and put our logo.png file in there.
Now we can simply reference /img/logo.png (note, we do not
specify public; that di‐
rectory is invisible to the client), and the static middleware will
serve that file, setting
the content type appropriately. Now let’s modify our layout so
that our logo appears on
every page:
<body>
<header><img src="/img/logo.png" alt="Meadowlark Travel
Logo"></header>
{{{body}}}
</body>

Dynamic Content in Views


The real power of views is that they can contain dynamic
information.

Let’s say that on the About page, we want to deliver a “virtual


fortune cookie.” In our app.js file, we define an array of fortune
cookies:

var fortunes = [
"Conquer your fears or they will conquer you.",
"Rivers need springs.",
"Do not fear what you don't know.",
"You will have a pleasant surprise.",
"Whenever possible, keep it simple.",
];
Modify the view (/views/about.handlebars) to display a fortune:

<h1>About Meadowlark Travel</h1>


<p>Your fortune for the day:</p>
<blockquote>{{fortune}}</blockquote>
Now modify the route /about to deliver the random fortune
cookie:
app.get('/about', function(req, res){

var randomFortune =

fortunes[Math.floor(Math.random() * fortunes.length)];

res.render('about', { fortune: randomFortune });

});

Initial Steps | 27Now if you restart the server and load the /about
page

The Request and Response Objects


HTTP Request Methods
The HTTP protocol defines a collection of request
methods (often referred to as HTTP verbs) that a client
uses to communicate with a server. Far and away, the
most common methods are GET and POST.
When you type a URL into a browser (or click a link), the
browser issues an HTTP GET request to the server. The
important information passed to the server is the URL
path and querystring. The combination of method, path,
and querystring is what your app uses to determine how
to respond.
For a website, most of your pages will respond to GET
requests. POST requests are usually reserved for sending
information back to the server (form processing, for
example).

Templating with Handlebars :


Choosing a Template Engine
In the Node world, you have many
templating engines to choose from,
so how to pick?
It’s a complicated question, and very
much depends on your needs. Here
are some
criteria to consider, though:
Performance
Clearly, you want your templating
engine to be as fast as possible. It’s
not something
you want slowing down your
website.
Client, server, or both?
Most, but not all, templating engines
are available on both the server and
client
sides. If you need to use templates
in both realms (and you will), I
recommend you
pick something that is equally
capable in either capacity.
Abstraction
Do you want something familiar (like
normal HTML with curly brackets
thrown
in, for example), or do you secretly
hate HTML and would love
something that
saves you from all those angle
brackets? Templating (especially
server-side tem‐
plating) gives you some choices
here.

Handlebars Basics
The key to understanding templating is understanding the concept of context. When

you render a template, you pass the templating engine an object called the context ob‐

ject, and this is what allows replacements to work.

For example, if my context object is { name: 'Buttercup' }, and my template is


<p>Hello, {{name}}!</p>, {{name}} will be replaced with Buttercup. What if you

want to pass HTML to the template? For example, if our context was instead { name:

'<b>Buttercup</b>' }, using the previous template will result in <p>Hello,

<b>Buttercup<b></p>, which is probably not what you’re looking for. To

solve this problem, simply use three curly brackets instead of two: {{{name}}}.

Comments
Comments in Handlebars look like {{! comment goes here }}. It’s important to un‐

derstand the distinction between Handlebars comments and HTML comments. Con‐

sider the following template:

{{! super-secret comment }}

<!-- not-so-secret comment -->

Assuming this is a server-side template, the super-secret comment will never be sent to

the browser, whereas the not-so-secret comment will be visible if the user inspects the
HTML source. You should prefer Handlebars comments for anything that exposes im‐

plementation details, or anything else you don’t want exposed.

to add a node package that provides Handlebars support for

Express:

npm install --save express3-handlebars

Then we’ll link it into Express:

var handlebars = require('express3-handlebars')

.create({ defaultLayout: 'main' });

app.engine('handlebars', handlebars.engine);

app.set('view engine', 'handlebars');

Views and Layouts


A view usually represents an individual page on your website (though it could represent

an AJAX-loaded portion of a page, or an email, or anything else for that matter). By

default, Express looks for views in the views subdirectory.

A layout is a special kind of

view—essentially, a template for templates. Layouts are essential because most (if not

all) of the pages on your site will have an almost identical layout. For example, they
must

have an <html> element and a <title> element, they usually all load the same CSS files,

and so on. You don’t want to have to duplicate that code for every single page, which is

where layouts come in. Let’s look at a bare-bones layout file:

You might also like