Hosting a Node Server on Heroku

Lots of topics lined up for today!

The real meat that we are hungering for is hosting and running our node app live on the web.

There's much more, though:

Hosting The 3D Web Coder Source HTML and Index on GitHub Pages

Before getting to the coding side of things, let me mention some handy file management, documentation and search advantages that I gain by making use of the GitHub Pages functionality.

All of the HTML sources for The 3D Web Coder live in the 3dwc GitHub repository, so you can clone that to copy all the HTML source to your own local system for simple and efficient global searches, etc.

You can also chip in and help me improve it if you find any typos or bugs!

The project also includes a global blog post index that is updated for every new post.

The posts are consecutively numbered for easier reference, just like I have been doing since 2008 for the older sibling blog The Building Coder.

This post here and now is number 0006. The current post number for The Building Coder is 1300   :-)

For The Building Coder, though, so far, I only use the index and internal numbering for my own personal use, since its HTML sources include some occasional snippets of confidential information.

For The 3D Web Coder, you can use the global index to navigate your local copy of the repository.

Much more exciting, though, is the fact that the 3dwc GitHub repository uses the gh-pages branch and thus is automatically published to the web every time a new commit is pushed.

Therefore, you can look at the global index file – and all the other HTML source files too, of course – live on the web, directly in GitHub.

The index file, for instance, is accessible like this:

jeremytammik.github.io/3dwc

The index lists the following data for each post:

As said, every time I push to the GitHub repository, the files and web site displayed are all automatically updated.

I hope you find this useful.

Dear Reader of The Building Coder, please yell hard enough and I promise to do my best to publish the HTML sources and global index for that as well in a similar fashion.

A Cooler GitHub Pages Sample – developer-autodesk.github.io

If you like the idea of hosting your web site directly on GitHub, enabling easy access to modify content simply by pushing from the command line, support for an unlimited number of collaborators, and all the other goodies the technology supports, you will love this beautiful sample illustrating the Autodesk View and Data API:

The 3D Web is Happening Here and Now

Do you love open source and non-proprietary stuff?

Are you sensitive to the 3D web being a proprietary thing?

Well, it is not.

WebGL is everywhere, free, open, for everyone, and fast becoming an industry-wide global movement.

One nice example is this skateboard customizer.

It works beautifully on any of your browsers, whether mobile or desktop and does a great job making it simple to use with a mouse or a touch screen.

Some more traditional samples are SketchFab and CL3VER.

You can also easily grab content from one site, e.g. furniture in SketchUp SKP format from Herman-Miller and view it in real time on another, e.g. www.autodesk.com/viewers.

The 3D web is happening now, and it's the whole industry.

Advance your career by being a leader bringing 3D to your business – or get left behind with a stale 2D web site.

The Milan WebGL Workshop

Some news from the Milanese 3D web scene:

We are holding a series of hands-on workshops about WebGL.

We opted for an educational approach, addressing people with only a basic understanding of coding, JavaScript, and zero 3D experience; there will be small groups, each one with a "coach" at a 1-to-4 or 1-to-5 ratio.

Here is the Milan WebGL Workshop meeting draft.

Feedback is welcome!

Hosting a Node Server on Heroku

Working our way towards our first full-fledged web application, we looked at the following steps so far:

Now I want to host and run my server live and accessible on the big wild worldwide web using Heroku.

Once I have that in place, I can start implementing interesting things like 2D and 3D graphics display that can be driven from a desktop application or anywhere else I choose.

So here goes, assuming you have Node.js and npm already installed:

Voila!

My sample is live at the automatically generated URL stark-island-7518.herokuapp.com.

That took about ten minutes.

The initial Heroku getting started app uses express and just says 'Hello World!'

var express = require('express');
var app = express();

app.set('port', (process.env.PORT || 5000));
app.use(express.static(__dirname + '/public'));

app.get('/', function(request, response) {
  response.send('Hello World!');
});

app.listen(app.get('port'), function() {
  console.log("Node app is running at localhost:" + app.get('port'));
});

I replaced it by my own server code and added the dict_to_string JavaScript function to display the query string arguments:

function pluralSuffix( n ) {
  return 1 == n ? '' : 's';
}

function dotOrColon( n ) {
  return 0 == n ? '.' : ':';
}

// format dictionary values to a string

function dict_to_string(dict) {
  var keys = Object.keys(dict);
  var n = keys.length;
  var s = [];

  s.push( n.toString() + ' key-value pair'
         + pluralSuffix( n ) + dotOrColon( n ) );

  keys.sort();
  for( var i = 0; i < n; ++i ) {
    s.push( '  ' + keys[i] + ' = ' + dict[keys[i]] );
  }
  return s.join('\n');
}

http = require('http'),
url = require('url'),
server = http.createServer(
  function(request,response){
    var paramdict = url.parse(request.url,true).query;
    response.writeHead(200, {'Content-Type': 'text/plain'});
    response.end(dict_to_string(paramdict));
  });
server.listen(1337, '127.0.0.1');
console.log('Server running at http://127.0.0.1:1337/');

I cannot simply use the command line git push to update it on GitHub, though.

An attempt to do so causes an error:

remote: Permission to heroku/node-js-getting-started.git denied to jeremytammik.
fatal: unable to access 'https://github.com/heroku/node-js-getting-started.git/': The requested URL returned error: 403

Using git push heroku master does the trick.

Well, actually not quite. An application error occurred. Good thing I still have the getting started guide open and can view my logs.

In the log file, I see the error 'Error R10 (Boot timeout) -> Web process failed to bind to $PORT within 60 seconds of launch'.

That makes total sense, since I can see that the express version of the server calls app.set('port', (process.env.PORT || 5000));, whereas my non-express version does not.

Meseems the simplest solution will be to graft my dict_to_string into the original Heroku express node server sample.

The server implementation now looks like this, plus the unchanged dict_to_string definition, of course:

var express = require('express');
var url = require('url');

var app = express();

app.set('port', (process.env.PORT || 5000));
app.use(express.static(__dirname + '/public'));

app.get('/', function(request, response) {
  var paramdict = url.parse(request.url,true).query;
  response.send(dict_to_string(paramdict));
});

app.listen(app.get('port'), function() {
  console.log("Node app is running at localhost:" + app.get('port'));
});

Lo and behold, it works!

Node server on Heroku

Here is the entire server script index.js renamed to node_index_query_string.js.

Testing a Node Server Running Live on the Web Live on this Page

Now it is globally accessible, we can test it right here from this page.

First, I'll implement a couple of minimal JavaScript functions to clean up your input for you and massage it into a valid query string to append to the Heroku server URL:

function cleanup_key_or_value(s) {
  return s
    .replace(/[\.,-\/#!$%\^&\*;:{}=\-_`~()]/g,"")
    .replace(/^\s+|\s+$/g,"");
}

function cleanup_key_value_pair(pair) {
  kv = pair.split('=').map(cleanup_key_or_value);
  return kv.join('=')
}

function make_query_string(s) {
  pairs = s.split(',').map(cleanup_key_value_pair);
  return pairs.join('&');
}

function submit_form(s)
{
  base_url = 'https://stark-island-7518.herokuapp.com/';
  query_string = make_query_string( s );
  window.open(base_url + '?' + query_string,
              'node_server','width=600,height=100');
}

Now, the following form just has to call submit_form(this.form.input.value) when the button is clicked:

Input a couple of comma-separated key=value pairs, e.g.:


See? It really does work.