Get Started Writing Web Apps with Node.js: Using the All Powerful NPM

34

In a previous article, I provided a quick introduction to Node.js and explained what it is, what it does, and how you can get started using it. I mentioned a few modules that can help you get things done, and they all — pug, ejs, and express — are external modules that will need to be installed using Node.js’s npm tool.

It’s definitely worth your time to learn more about npm. It is mighty powerful and it doesn’t just install modules; it also helps you set up a whole environment for your application. But, let’s not jump the gun. First, let’s just use npm for what it’s used for most: installing modules.

In this article, I’ll show how to create a project around what’s called a “single-page web application.” In a traditional web application, each time you click on a link or fill in and submit a form, you are directed to another page that shows the result of your actions.

Not with a single-page application. In a single-page application, you only see one page but its content changes as you interact with it. In this example, you will have the main page present a form with a textbox and submit button (Figure 1). When you fill in the box and press Submit, you will be redirected back to the same page (or so it will seem) and the word you typed into the text box will show up below the form.

Figure 1: This is the single-page web app you’re going to build.

To get started, create a directory and call it, say, form. Then cd into it and create an empty text file called server.js. This is where the code for your web application will go.

Next, running npm init. npm will ask you for some information, such as the name of the project, the version, a description, the entry point (i.e., what file you are going to make Node execute), the Git repository where you’re going to store the project, and so on. When you’re done, npm generates a package.json file that looks something like this:

{
 "name": "form",
 "version": "1.0.0",
 "description": "Example of single-page web app.",
 "main": "server.js",
 "scripts": {
   "test": "echo "Error: no test specified" && exit 1",
   "start": "node server.js"
 },
 "repository": {
   "type": "git",
   "url": "git+ssh://git@github.com/yrgithubaccount/nodejsform.git"
 },
 "keywords": [
   "example",
   "form",
   "get",
   "post",
   "node.js"
 ],
 "author": "Your Name",
 "license": "GPL-3.0",
 "bugs": {
   "url": "https://github.com/yrgithubaccount/nodejsform/issues"
 },
 "homepage": "https://github.com/yrgithubaccount/nodejsform#readme"
}

Let’s install express and also body-parser. Run:

npm install express --save

inside your project’s directory, and you will see something like Figure 2.

Figure 2: Installing express with npm.
That is a tree view of all of express’s dependencies. If you list your directory now, you will also see a new subdirectory called node-modules. That’s where all the code for installed modules live. Notice how convenient this is. You could’ve install express globally with:

npm install express -g

But by installing by default locally and only in your project’s directory, npm makes sure you don’t clutter up your main module directory.

Next, install body_parser with:

npm install body-parser --save

This module makes sure you will be able to parse easily the data you get from your form.

The –save modifier in the install commands above tells npm to include the information about the modules you’re going to use with your project into the package.json file. Check it out:

{
 "name": "form",
 "version": "1.0.0",
 "description": "Example of single-page web app.",
 "main": "server.js",
 "scripts": {
   "test": "echo "Error: no test specified" && exit 1",
   "start": "node server.js"
 },
 "repository": {
   "type": "git",
   "url": "git+ssh://git@github.com/yrgithubaccount/nodejsform.git"
 },
 "keywords": [
   "example",
   "form",
   "get",
   "post",
   "node.js"
 ],
 "author": "Your Name",
 "license": "GPL-3.0",
 "bugs": {
   "url": "https://github.com/yrgithubaccount/nodejsform/issues"
 },
 "homepage": "https://github.com/yrgithubaccount/nodejsform#readme,
 "dependencies": {
   "body-parser": "^1.15.2",
   "express": "^4.14.0"
 }
}

With that, if you want to share your project or upload it to your Git repository, you don’t need to upload all the modules, too. As long as they have the package.json file, other users can clone your project. They can just run npm install, without any other arguments, and npm will download and install all the dependencies automatically. How useful is that?

Let’s write the code for server.js:

var express = require('express'),
   app = express(),
   bodyParser = require('body-parser'),
   fs= require('fs');

app.use(bodyParser.urlencoded({ extended: true }));

fs.readFile('./head.html', function (err, head) {
   if (err) {
       res.sendStatus(500).send('Couldn't read head!');
       res.end();
   }
   fs.readFile('./form.html', function (err, form) {
       if (err) {
           res.sendStatus(500).send('Couldn't read form!');
           res.end();
       }
       fs.readFile('./foot.html', function (err, foot) {
           if (err) {
               res.sendStatus(500).send('Couldn't read foot!');
        res.end();
           }

           app.get('/', function (req, res) {
               res.send(head + form + foot);
               res.end();

               console.log("Got a GET");
           });

           app.post('/', function (req, res) {
               res.send(head + form + '<p>' + req.body.name + '</p>n' + foot);
               res.end();

               console.log("Got a POST");
           });

           var server = app.listen(8081, function () {
           console.log("Example app listening at http://127.0.0.1:8081")
           });
           
       });
   });
});

Let’s see what this does step by step:

  • var express = require(‘express’), app = express() drags in express and then initiates an express application.

  • bodyParser = require(‘body-parser’), drags in body-parser and creates a body-parser object.

  • fs= require(‘fs’);, as in our first example, brings in Node.js’s in-built file-managing module.

  • app.use(bodyParser.urlencoded({ extended: true })); adds body-parsing superpowers for urlencoded data to our express app.

  • The block of chained fs.readFile(‘./some_HTML_file’, function (err, some_variable) {… instructions is similar to the one you saw previously. First, you try to open head.html; if that succeeds, you dump the content into the head variable, and then try and open form.html and dump its contents into the form variable. Finally, open the foot.html file and dump its contents into the foot variable.

  • If the server manages to open all three HTML files, you start listening for GET calls to your server. If you receive one (app.get(‘/’, function (req, res) {), you concatenate all the contents of the files together and send it out to the client (res.send(head + form + foot); res.end();). The server prints a message to the console for debugging purposes. (console.log(“Got a GET”);).

  • The moment you hit the Submit button, you’re sending a POST request to the server. The form is linked up to the same page (see form.html below) it is sent from. This is what app.post(‘/’, function (req, res) { picks up. This is probably the most interesting thing of this exercise. the fact that you can have the express app respond with a different virtual page at the same address, its content depending on the type of request the server receives.

  • res.send(head + form + ‘<p>’ + req.body.name + ‘</p>n’ + foot); grabs the data coming from the name text field in the form (again, see form.html below) and inserts it into the HTML text the server sends back to the web browser.

  • var server = app.listen(8081, function () { starts the server on port 8081.

For reference, the three HTML files look like this:

head.html

<html>
   <body>

form.html

<form action="http://127.0.0.1:8081/" method="POST">
   Name: <input type="text" name="name">  <br>
   <input type="submit" value="Submit">
</form>

foot.html

   </body>
</html>

Templating like this is of course very primitive, but you get the idea.

You could expand this into an app that stores the names in a database and then sets up a system for users with different privileges — and there are modules for that. Or, you could change the app to upload images or documents and have your server show them in a gallery dynamically as you upload them — there are also modules for that. Or any of the million other things Node.js and its army of modules lets you do in a few lines of code.

Conclusion

So, saying Node.js is merely a JavaScript interpreter is unfair. Node.js, just by itself may seem underwhelming at first glance. But, when you delve into it further, the possibilities seem just about endless.

What with all the modules, and the amazingly active community, the scope of projects that Node.js makes possible is staggering. It is little wonder that it powers complex web applications such as those used by Netflix, PayPal, LinkedIn, and many others.

Want to learn more about developing applications? Check out the “Developing Applications with Linux” course from The Linux Foundation.