Sunny.js Presentation

I gave a lightning talk at last night’s Node.js Meetup introducing Sunny.js, a multi-cloud library for Node.js. For more background on Sunny, see my previous blog post to get started with the library.

Instead of the usual PowerPoint deck, I used Prezi, which I have been wanting to try out for some time. Here is the Sunny.js prezi I gave at the meetup:

Although the Prezi took some time to put together (especially being my first time using the service), I was very happy with the appearance and flow of the presentation.

Simple Cloud/Web Proxy Server

As part of my presentation, I demo’ed a simple proxy service using Sunny and Node. I took the v0.0.1 HTML documentation for Sunny, and uploaded all of it to an Amazon S3 bucket, being careful to preserve paths from the original documentation files when naming S3 keys. (Actually, this wasn’t hard at all – I just used the reliable CyberDuck S3 client).

I then wrote a really simple 40-line web server. It basically takes credentials from the process environment, checks if a specified container exists, and then translates web request GET paths to blob names in the container I set up. The result is that I could serve my entire documentation site straight from by Amazon S3 bucket!

The source for the project, sunny-proxy, is available on GitHub, and is fairly straightforward to setup for yourself using the Readme instructions.

For the impatient, here’s the entire relevant code for the web server:

var http = require('http'),
  mime = require('mime'),
  sunny = require('sunny'),
  conn = sunny.Configuration.fromEnv().connection,
  ADDR = process.env.ADDRESS || "0.0.0.0",
  PORT = process.env.PORT || 2000,
  CONTAINER = process.env.SUNNY_PROXY_CONTAINER;

// Get our container and create server inside to get blobs.
conn.getContainer(CONTAINER, { validate: true })
  .on('error', function (err) {
    console.log(err);
    throw err;
  })
  .on('end', function (results) {
    // We have a valid container, so let's create the server now.
    http.createServer(function (req, res) {
      var path = req.url.replace(/\/$/, "/index.html").replace(/^\/*/, ""),
        status = 200,
        logResult = function () {
          console.log("[%s] %s", status, path); },
        stream;

      // Header based on MIME type (re-write on error).
      res.writeHead(status, { 'content-type': mime.lookup(path) });

      // Get blob and pass through error or pipe to response.
      stream = results.container.getBlob(path);
      stream.on('error', function (err) {
        status = err.statusCode || 500;
        res.writeHead(status, { 'content-type': "text/html" });
        res.end("<h1>" + status + ": " + err.message + "</h1>");
        logResult();
      });
      stream.on('end', logResult);
      stream.pipe(res);
      stream.end();
    }).listen(PORT, ADDR);
    console.log("Server running at http://%s:%s/", ADDR, PORT);
  })
  .end();

We use the magic of stream.pipe(res) to handle all of the transfer details of passing through our blob data chunks to the HTTP response.

I even took it a step further and set up a simple Heroku app to run the application. All it took was a quick review of the Node app instructions and a “Procfile” file (mine is available in the GitHub repo) and I was able to get my node proxy server up and running on the web in under a half hour! Moreover, I was pleasantly surprised at how fast the web application was running – especially considering the web server doesn’t use any caching logic or any intelligent optimizations that a real web server would.

The Sunny-based proxy server certainly isn’t anything amazing or revolutionary – it just serves blobs as if they were static files for a web server – but it does show just how easily Node.js and libraries like Sunny can glue cloud / service-based components together for fast and scalable applications.