Skip to content

Instantly share code, notes, and snippets.

@jmervine
Last active August 29, 2015 13:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jmervine/9203722 to your computer and use it in GitHub Desktop.
Save jmervine/9203722 to your computer and use it in GitHub Desktop.
MaxCDN Node.js Blog Draft

An Introduction to MaxCDN on Node.js

In addition to MaxCDN's powerful Oauth API, they offer a number of simple modules for various languages. Here I'll be covering they're Node.js module.

In this post, I'll go over some basic examples of how to display reports and purge caches using the MaxCDN Node module, which like all of MaxCDN's modules, is open sourced at github.com/MaxCDN/node-maxcdn.

If you're like me and prefer to read up on the technologies you'll be using in this post before diving in, here's what we'll be using:

  • Node.js, "a platform built on Chrome's JavaScript runtime for easily building fast, scalable network applications"
  • npm, "Node Packaged Modules"
  • Express, "a web application framework for node"
  • Jade, a templating engine for Node
  • Bootstrap, "The most popular front-end framework for developing responsive, mobile first projects on the web."
  • jQuery, "a fast, small, and feature-rich [client-side] JavaScript library"

Setup

Before getting started, we'll need to make we've installed Node and the modules we'll need.

Node.js

Check that Node is installed and you're running a more recent version. The example's contained with in this post have been tested using 0.10.26 (the latest at the time of writing this), but any 0.10.x (and probably 0.8.x) version should do.

$ node --version
v0.10.26

Here are some links to help you on your way, if you haven't installed Node yet.

Install Required Modules

I like to create an empty package.json file, allowing npm's --save flag to store our installed packages for later use. You can also use npm init, if you're planning on building a package for later installation via npm. Optionally, you can skip this all together and omit the --save option in the npm command below.

$ echo '{}' > package.json 

Next, we'll install the modules we'll be using for the examples in this post. By default, npm installs modules locally to the directory you're in when installing (in ./node_modules), so ensure that you're an acceptable working directory before running the next command. If you need to change directories, you should move your package.json as well.

$ npm install --save maxcdn express jade
# npm output omitted ...

If you saved the install, package.json will look something like this:

{
  "dependencies": {
    "maxcdn": "^0.1.3",
    "express": "^3.4.8",
    "jade": "^1.1.5"
  }
}

Express

If you haven't used Express, that's okay. What I've included here is a good basic example of of how to setup simple application without prior knowledge of the framework. That said, I recommend that you read more deeply into best practices, as the way I'm implementing this application is suitable for smaller applications, but isn't as maintainable on a larger scale.

We'll start by creating a the file app.js and initializing MaxCDN Node module and creating a variable containing the id of the zone we'll be working with. Notice I'm pulling the required data from my environment (set via export ALIAS=MY_ALIAS, etc.). However, feel free to hardcode them, or better yet, abstract them to a configuration file.

// file: app.js
'use strict';
var MaxCDN  = require('maxcdn');

// Initialize maxcdn from environment.
var maxcdn  = new MaxCDN(process.env.ALIAS,
                         process.env.KEY,
                         process.env.SECRET);

// For this example, I'll restrict to a single zone,
// however, it wouldn't be hard to adapt this for
// multiple zones.
var zoneid = 12345;

Now that we have a maxcdn instance to work with in our application, let's get Express setup with basic logging and a few simple routes to hit.

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

// A little logging gose a long way.
app.use(express.logger('dev'));

// main route
app.get('/?', function (req, res) {
    res.send('Hello!');
});

// purge zone cache route
app.get('/purge/?', function (req, res) {
    res.send('Purge!');
});

// clear file cache route
app.get('/purge/*', function (req, res) {
    res.send('Purge '+req.params+'!');
});

app.listen(3333, function (err) {
    if (err) {
        console.trace(err);
    } else {
        console.log('Started on port 3333!');
    }
});

Start the app by running node app.js and using a browser, hit the following end points:

The results should be something like the following.

app1.png

Displaying Something Useful

We have a basic Express application in place and know that routes properly. Let's get our main page displaying a report of our popular files from MaxCDN's API, and do so with style. Bootstrap provides a simple scaffolding for building applications. With the added support of BootstrapCDN and the Bootswatch templates it hosts, it makes styling up a simple application like this stupid simple. As I mentioned before, for templating we'll be using the Jade templating engine to generate markup. Jade is a simple tab based templating engine (much like Haml), which relies on indentation to build structured, well-indented and clear markup.

To support Jade, we'll need to make a few tweaks to our Express setup.

In app.js, after your app definition, add the following:

// Tell Jade where our templates are.
app.set('views', __dirname + '/views');

// Tell Express to use Jade as it's templating engine.
app.set('view engine', 'jade');

// Here, we're not using any external assets, but if we were, we'd tell
// Express where to find them with the following...
app.use(express.static(__dirname + '/public')); // Support 

Using MaxCDN's API, we'll have our main route do a simple fetch on the reports/popularfiles.json endpoint and pass it to our template for rendering.

app.get('/?', function(req, res) {
    // Fetch popularfiles from MaxCDN
    maxcdn.get('reports/popularfiles.json', function(err, data) {
        // Handle errors, should they arise.
        if (err) {
            console.trace(err);
            res.send(500, err);
            return;
        }

        // Render 'index.jade' with popularfiles object.
        res.render('index', { popularfiles: data.data.popularfiles });
    });
});

With our popular files from MaxCDN available, let's build a basic template to display the information, leveraging Bootstrap for a simple and clean look. Create ./views/index.jade and add the following to it.

doctype html5
html
  head
    title MaxCDN Popularfiles

    meta(charset='utf-8')
    meta(name='viewport', content='width=device-width, initial-scale=1')

    //- Include Bootstrap from BootstrapCDN
    link(href="//netdna.bootstrapcdn.com/bootswatch/3.1.1/united/bootstrap.min.css", rel="stylesheet")

  body
    //- Header / Title Bar
    .navbar.navbar-default.navbar-static-top
        .navbar-header
            a.navbar-brand(href="/") MaxCDN Popularfiles

    //- Main Body
    .container
      .table-responsive
        table.table.table-striped
          thead
            tr
              th File
              th Hits
          tbody
            - for entry in popularfiles
              tr
                td= entry.uri
                td= entry.hit

    //- Footer Information
    footer
      center
        p Powered by 
          a(href="http://maxcdn.com") MaxCDN

After saving our files and restarting our app (node app.js), we should see something like this:

ss1.png

Note: If you're getting errors from MaxCDN, ensure that all your credentials are correct and that the host you're working on is whitelisted in your MaxCDN Account. For questions see MaxCDN's Authentication Documentation.

Cache Purge

What we have built above is good enough for most public use cases. In fact, it's a simplified version of what's used on BoostrapCDN for displaying usage information. That said, one of the more common usages of CDN APIs in general is automating the purging cached files. So to take this example a step further, let's add some buttons to our page to purge indivial files, or the entire zone in one shot.

To do so, we'll need update to our Express app, modifing the /purge routes that we setup early to run a maxcdn.delete on the zones cache endpoint, both with and without specifying a file. When no file is specified, the entire cache is purged.

In app.js replace the two purge end points we created earlier with the follow code sample.

app.get('/purge/?', function(req, res) {
    // Purge entire zone.
    maxcdn.delete('zones/pull.json/'+zoneid+'/cache', function(err, data) {
        if (err) {
            console.trace(err);
            res.send(500, err);
            return;
        }

        // Return status.
        res.send(data.code);
    });
});

// purge file cache route
app.get('/purge/*', function(req, res) {
    var files = { files: [ '/'+req.params ] };

    // Purge requested file.
    maxcdn.delete('zones/pull.json/'+zoneid+'/cache', files, function(err, data) {
        if (err) {
            console.trace(err);
            res.send(500, err);
            return;
        }

        // Return status.
        res.send(data.code);
    });
});
// ...

With that, our application ow supports purging zones and it's files, we'll need to add some buttons to our page to initiate the purge. In views/index.jade, replace the previous table tag with the following.

        table.table.table-striped
          thead
            tr
              th File
              th Hits
              th(width=100)
                button.btn.btn-primary(value='') Purge All
          tbody
            - for entry in popularfiles
              tr
                td= entry.uri
                td= entry.hit
                td
                  button.btn.btn-primary(value=entry.uri) Purge

Button's are pretty, but they don't actually do anything anything on their own. Using jQuery, let's add some magic to submit an aJax request back to our app, requesting a cache purge and waiting for a response. In addition, we'll include a few bells and whistles, like modifing the style on our buttons to show the status of our purge, and a simple text based spinner to show that the purge is in action (purges take anywhere from 10-30 seconds).

If you're not that familar with jQuery, simply copy and paste this inside the head tag (ensuring proper indenting, as always with Jade).

    //- Include jQuery
    script(src='http://code.jquery.com/jquery-2.1.0.min.js')
    script.
      $(window).load(function() {
        $('button').each(function() {
          //- Add click event to all buttons.
          $(this).click(function() {
            //- Build purge url string from button value.
            var url = '/purge'+$(this).attr('value');

            var that = $(this);

            //- Add a simple text spinner while pruging.
            var spinner = [ '|', '/', '---', '\\' ];
            var spinIdx = 0;

            function ticker() {
              if (spinIdx == spinner.length) {
                spinIdx = 0;
              }
              that.html(spinner[spinIdx++]);
            }

            ticker();
            var interval = setInterval(function() {
              ticker();
            }, 1000);

            // Update button style.
            that.removeClass('btn-primary');
            that.addClass('btn-warning');
            that.addClass('disabled');

            // Sumbit Ajax purge request.
            $.ajax(url)
              .always(function() {
                // On pass or fail, cleanup.
                clearInterval(interval);
                that.removeClass('disabled');
                that.removeClass('btn-warning');
              })
              .done(function() {
                // On success, notify.
                that.html('Complete');
                that.addClass('btn-success');
              })
              .fail(function() {
                // On error, notify.
                that.html('ERROR!');
                that.addClass('btn-danger');
              });
          });
        });
      });

That's it! We now have a simple, easy on the eyes application that allows us to see the most popular file's being loaded via our MaxCDN account. As an added bonus we're able to purge our cache or a single file from the cache, at the click of a button.

ss2.png

Completed Example

Consider this the TL;DR. You can grab the completed code samples used in this post here.

What next?

MaxCDN's APIs offer a ton of functionality to interact with your account and report on it's usage. For more examples using the MaxCDN Node Module, visit github.com/MaxCDN/node-maxcdn and checkout the README and examples included there. For more information on MaxCDN's Oauth API, visit docs.maxcdn.com.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment