The Quest Example

This example is a bit more elaborate and uses some add-on modules, installed using NPM. Then we'll see some callback-based I/O.

The Express Module

A popular module for routing and many other things is called Express. Here is some information on routing. To install it, see installing. I won't go over that.

Express Example

Here's the code for the express example. As you can see, the single responder callback has been broken up into a collection of handlers for particular routes that are matched against the URL, just like in Flask.

One important difference is that in Flask, both methods are combined in a single handler (and we distinguish them by looking at request.method), but here we differentiate by saying app.get(); we would say app.post() to support a POST method.

var myPort = 1942;

var express = require('express');

var app = express();

// respond with "hello world" when a GET request is made to the homepage
app.get('/', function (req, res) {
  res.send('hello world');
});

app.get('/hello/', function (req, res) {
    res.send('Hello to you, too!');
});

app.get('/bye/', function (req, res) {
    res.send('Come back soon!');
});

function collatzNext(n) {
    return ( n % 2 === 0 )? n / 2 : 3 * n + 1;
}

app.get('/collatz/:start', (req, res) => {
        // a simple computation
        var num = req.params.start;
        var next = collatzNext(num);
        // var resp = 'num is '+num+' and next is '+next;
        var resp = 'num is '+num+' and next is <a href="/collatz/'+next+'">'+next+'</a>';
        console.log(resp);
        res.send(resp);
});

app.listen(myPort, () => console.log(`Example app listening on port http://0.0.0.0:${myPort}!`));

Notice the parameterized URL, this time using colons instead of angle brackets: /collatz/:start rather than /collatz/<start>.

So, given your knowledge of Flask, the learning curve for Node and Express is much less steep.

QuestForm Example

Our last example has two routes, both matching /

  • GET reads an HTML file from disk. That HTML file contains a form to fill out. The form posts to the / route.
  • POST gets the form data that was submitted, and writes (appends) it to a log file of the form submissions.

Both reading the HTMl file from disk and appending to the log demonstrate the callback-style coding.

Here's the code:

var myPort = 1942;

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

var app = express();

// set up static file serving, served out of the 'static' folder:
// we'll use this for CSS and our logo

app.use(express.static('static'))

// for parsing application/xwww-
app.use(bodyParser.urlencoded({ extended: true })); 

app.get('/', function (req, res) {
    // A templating system would probably be better, and it is 
    // inefficient to read the file every time, but what the heck
    fs.readFile('questform.html', function (err, data) {
        if(err) {
            return console.error(err);
        }
        res.writeHead(200, {'Content-Type': 'text/html'});
        res.write(data);
        res.end();
    });
});

// The questform will submit to the empty string,
// which is the same route, but using POST

app.post('/', function (req, res) {
    console.log('body')
    // the bodyParse creates this, as JS object with the form data
    console.log(req.body);
    fs.appendFile('questform.log',
                  // JSON is easy to parse
                  JSON.stringify(req.body)+'\n',
                  function (err, data) {
                      if(err) {
                          console.log('error writing to questdata.log: '+err);
                      }
                  });
    // happens concurrently with writing the log
    res.writeHead(200, {'Content-Type': 'text/html'});
    res.write('Thanks for your submission');
    res.end();
});


const msg = `Example app listening on port http://0.0.0.0:${myPort}!`;
app.listen(myPort, () => console.log(msg));