Server Reads Requested Assets

You have wondered, and why the server does not respond with real HTML5, and not generated HTML5 fragments. Until now this has been done to show the structure of a server. Now we want more.

Following the best practice outlined in the section called “Project Creation - Best Practice” we create a project myg60new remotely, clone it, prepare the package.json, and before we get to the server, we create a project subdirectory views, and in that we create a boilerplate index.html for welcoming users to our site. The static front page if you will.

Example 17.1. Boilerplate Front Page, myg60new/views/index.html
<!doctype html>
<html>
    <head>
        <meta charset="utf-8"/>
        <title>myg6n Home Page</title>
    </head>
    <body>
        <header>
            <h1>Welcome World!</h1>
        </header>
        <main>
            <p>
                To our regular old fashioned frontend static homepage.
            </p>
        </main>
        <footer>
            <p>
                &copy; nml
            </p>
        </footer>
    </body>
</html>

We shall get back to that page. First we adapt the modularized project code from the previous section. You will notice that some of the modules are written in such a way that they have become invariant, project agnostic, so that they can be used unchanged in all native Node.js projects.

Keeping the naming convention standard in all projects, the invariant code is in main.js, and in server.js. The routing and handling is certainly project specific, because it holds the concrete logic for the application, so they vary.

Example 17.2. Routed and Modularized Application, myg60new/main.js, Unchanged!
"use strict";

var server = require("./server");                   // make server module available
var router = require("./router");                   // router module

server.start(router);                               // start server
                                                    // callback to route

Example 17.3. The Server as a Module, myg60new/server.js, Unchanged!
"use strict";
/*
 *  new server.js adds request body data
 */
const http = require("http");                   // http module
const lib = require("../private/libWebUtil");   // home grown utilities
const hostname = "localhost";
const port = Number(process.argv[2]) || 3000;

module.exports = {
    start(router) {
        const server = http.createServer();

        server.on("request", function (req, res) {      // eventhandler for "request"
            console.log(lib.makeLogEntry(req));         // home made utility for logging
            let body = [];
            req.on("data", function (bodyData) {        // eventhandling for data reception
                body.push(bodyData);                    // bodyData is an object
            });
            req.on("end", function () {                 // eventhandling for end-of-data
                body = Buffer.concat(body).toString();  // body2string
                router.route(req, res, body);           // pass to router
            });
        });

        server.listen(port, hostname, function () {
            console.log(`Log: Server started on http://${hostname}:${port}/`);
        });
    }
}

Example 17.4. The Router as a Module, myg60new/router.js

In this particular instance, we use the same project as in the previous section, so the following code remains unchanged beause our stepwise refinement is in the handlers.

"use strict";
/*
 * check if routed handler function exists
 * if yes call it, else complain
 */
const handlers = require("./handlers");               // handlers module

const requestHandlers = {                             // application urls here
    "/home": handlers.home,
    "/info": handlers.info,
    "/contact": handlers.contact,
    "/about": handlers.about,
    "/hello": handlers.hello,
    "/notfound": handlers.notfound,
}

module.exports = {
    route(req, res, body) {

        if (typeof requestHandlers[req.url] === 'function') { // look for route
            requestHandlers[req.url](req, res);               // if found use it
        } else {
            requestHandlers["/notfound"](req, res);           // use notfound
        }
    }
}

Example 17.5. The Handlers in a Module, myg60new/handlers.js
'use strict';
/*
 * handlers.js
 * Requesthandlers to be called by the router mechanism
 */
const fs = require("fs");                   // file system access
module.exports = {
    home(req, res) {
        fs.readFile("views/index.html", function(err, data) {
            if (err) {
                res.end("<h1>The page you wanted doesn't exist</h1>");
            }
            res.write(data);
            res.end();
        });
    },
    notfound(req, res) {
        console.log(`Log: No handler found for route ${req.url}.`);
        res.end();
    }
}

On your CLI do npm test to start the server. Then go to your browser and test the following url(s).

Check the browser screen as well as the console log in each case.