MongoDB Dynamic Pages with Node.js

Example 19.7. Dynamic Routes Router, routes/router.js
"use strict";

const handlers = require("../private/handlers");    // handlers module
const httpStatus = require("http-status-codes");
const contentTypes = {
    "text": { "Content-Type": "text/plain; charset=utf-8" },
    "start": { "Content-Type": "text/html; charset=utf-8" },
    "js": { "Content-Type": "application/js" },
    "css": { "Content-Type": "text/css" },
    "png": { "Content-Type": "image/png" },
    "jpg": { "Content-Type": "image/jpg" },
    "gif": { "Content-Type": "image/gif" },
    "ico": { "Content-Type": "image/x-icon" },
    "svg": { "Content-Type": "image/svg+xml" }
};

const routes = {                                    // register handles to routes
    "GET": {
        "/start": handlers.getAndRespond,
        "/side": handlers.findCities,
        "/about": handlers.getAndRespond,
        "/contact": handlers.getAndRespond,
        "js": handlers.getAndRespond,
        "css": handlers.getAndRespond,
        "png": handlers.getAndRespond,
        "jpg": handlers.getAndRespond,
        "gif": handlers.getAndRespond,
        "ico": handlers.getAndRespond,
        "svg": handlers.getAndRespond
    },

    "POST": {
        "/contact": handlers.receiveData
    }
};

exports.route = function(req, res, body) {          // routing
    let asset;
    let type;
    let routedUrl;
    if (req.url.indexOf(".js") !== -1) {            // check for asset types
        asset = "js";
        routedUrl = "public/javascripts" + req.url;
        type = contentTypes.js;
    } else if (req.url.indexOf(".css") !== -1) {
        asset = "css";
        routedUrl = "public/stylesheets" + req.url;
        type = contentTypes.css;
    } else if (req.url.indexOf(".png") !== -1) {
        asset = "png";
        routedUrl = "public/images" + req.url;
        type = contentTypes.png;
    } else if (req.url.indexOf(".jpg") !== -1) {
        asset = "jpg";
        routedUrl = "public/images" + req.url;
        type = contentTypes.jpg;
    } else if (req.url.indexOf(".gif") !== -1) {
        asset = "gif";
        routedUrl = "public/images" + req.url;
        type = contentTypes.gif;
    } else if (req.url.indexOf(".svg") !== -1) {
        asset = "svg";
        routedUrl = "public/images" + req.url;
        type = contentTypes.svg;
    } else if (req.url.indexOf(".ico") !== -1) {
        asset = "ico";
        routedUrl = req.url;
        type = contentTypes.ico;
    } else {
        if (req.url.charAt(req.url.length - 1) === "/") {
            asset = "/start";
            routedUrl = "views/index.html";
            type = contentTypes.html;
        } else if (req.url === "/start") {
            asset = req.url;
            routedUrl = "views/index.html";
            type = contentTypes.html;
        } else if (req.url === "/side") {
            asset = req.url;
            routes[req.method][asset](req, res);
            return;
        } else if (req.url === "/contact" && req.method === "POST") {
            asset = req.url;
            routes[req.method][asset](req, res, body);
            return;
        } else {
            asset = req.url;
            routedUrl = "views" + req.url + ".html";
            type = contentTypes.html;
        }
    }

    try {
        if (routes[req.method][asset]) {            // does handler exist to this route
            routes[req.method][asset](routedUrl, type, res);  // yes, call it with params
        } else {                                // no, return error msg
            res.writeHead(httpStatus.NOT_FOUND, contentTypes.text);
            res.end(`route for <kbd>${req.url}</kbd> not found`);
        }
    } catch (ex) {                              // routing exception
        console.log("Log: Routing exception: " + ex);
    }
};

Example 19.8. The Handlers, private/handlers.js
'use strict';
/*
 * handlers.js
 * Requesthandlers to be called by the routing mechanism
 */
const fs = require("fs");                           // file system access
const httpStatus = require("http-status-codes");
const lib = require("../private/libWebUtil");           // home grown utilities
const experimental = require("../private/myTemplater"); // highly experimental template
const experimental1 = require("../private/myCities"); // highly experimental template

const goError = function (res) {
    res.writeHead(httpStatus.NOT_FOUND, {   // http page not found, 404
        "Content-Type": "text/html; charset=utf-8"
    });
    res.write("<h1>404 Not Found</h1>");
    res.end();
};


const getAndRespond = function (path, contentType, res) {
    if (fs.existsSync(path)) {              // does file exist, sync
        fs.readFile(path, function(err, data) { // read
            if (err) {                      // if read error
                console.log("nml: " + err);           // inform server
                goError(res);               // inform user
                return;                     // back to caller
            }
            res.writeHead(httpStatus.OK, contentType); // prep header
            res.write(data);                // prep body with read data
            res.end();                      // send response
        });
    } else {
        goError(res);                       // doesnt exist error
    }
}

const receiveData = function (req, res, data) {
    let obj = lib.makeWebArrays(req, data);         // home made GET and POST objects
    res.writeHead(httpStatus.OK, {                  // yes, write relevant header
        "Content-Type": "text/html; charset=utf-8"
    });
    res.write(experimental.receipt(obj));           // home made templating for native node
    res.end();
}

const findCitiesOld = function (req, res) {
    const mongo = require('mongodb');
    const dbname = "world";
    const constr = `mongodb://localhost:27017`;

    mongo.connect(
        constr, { useNewUrlParser: true, useUnifiedTopology: true},
                                                    function (error, con) {
        if (error) {
            throw error;
        }
        const db = con.db(dbname);                  // make dbname the current db
        /* Retrieve,
         * reads cities from the database
         */
        db.collection("city").find().toArray(function (err, city) {
            if (err) {
                throw err;
            }
            res.writeHead(httpStatus.OK, {                  // yes, write relevant header
                "Content-Type": "text/html; charset=utf-8"
            });
            res.write(experimental1.cities(city));           // home made templating for native node
            res.end();
            con.close();
        });
    });
}

const getAndDisplay = async function (req, res, dbName, coll, query) {
    const mon = require('./monModelMod');
    let result = await mon.mongon.mongoFind(dbName, coll, null);
    console.log(result);
    res.write(experimental1.cities(result));           // home made templating for native node
    res.end();
}

const findCities = function (req, res) {
    const dbName = "world";
    const coll = "city";
    getAndDisplay(req, res, dbName, coll, null);
    console.log("if you see me first, it asynch");
}

exports.getAndRespond = getAndRespond;
exports.receiveData = receiveData;
exports.findCitiesOld = findCitiesOld;
exports.getAndDisplay = getAndDisplay;
exports.findCities = findCities;

Example 19.9. Dynamic Content Page Template, private/myCities.js
/* myCities.js Home made experimental templating */
"use strict";

const cities = function(obj) {
    let htmltop = `<!doctype html>
<html>
    <head>
        <meta charset="utf-8"/>
        <title>McKilroy's Second Test Template</title>
        <link rel="stylesheet" href="side.css"/>
    </head>
    <body>
        <header>
            <h1>Kilroy's Cities</h1>
            <nav>
                <ul>
                    <li><a href="/">Home</a></li>
                    <li><a href="/side">Side</a></li>
                    <li><a href="/about">About</a></li>
                    <li><a href="/contact">Contact</a></li>
                </ul>
            </nav>
        </header>
        <div>`;

    let htmlbot = `        </div>
    </body>
</html>`;

    let dynamic = "";
    dynamic += `<p><em>${obj[0].name}</em></p>`;


    return htmltop + dynamic + htmlbot;
}

exports.cities = cities;

On your CLI do npm test to start the server. Then go to your browser and test the menu items. Check the browser screen as well as the console log in each case.