Node.js 101: Wrap up

Year of 101s, Part 1 – Node January

Summary – What was it all about?

I set out to spend January learning some node development fundementals.

Part #1 – Intro

I started with a basic intro to using node – a Hello World – which covered what node.js is, how to create the most basic of all programs, and mentioned some of the development environments.

Part #2 – Serving web content

Second was creating a very simple node web server, which covered using nodemon to develop your node app, the concept of exports, basic request routing, and serving various content types.

Part #3 – A basic API

Next was a simple API implementation, where I proxy calls to the Asos API, return a remapped subset of the data returned, reworked the routing creating basic search functionality and a detail page, and touched on being able to pass in command line arguements.

Part #4 – Basic deployment and hosting with Appharbor, Azure, and Heroku

Possibly the most interesting and fun post for me to work on involved deploying the node code on to three cloud hosting solutions where I discovered the oddities each provider has, various solutions to the problems this raises, as well as some debugging cleverness (nice work, Heroku!). The simplicity of a git-remote-push-deploy process is incredible, and really makes quick application development and hosting even more enjoyable!

Part #5 – Packages

Another interesting one was getting to play with node packages, the node package manager (npm), the express web framework, jade templating engine, and stylus css pre-processor, and deploying node apps with packages to cloud hosting.

Part #6 – Web-based development

The final part covered the fantastic Cloud9IDE, including a (very) basic intro to github, and how Cloud9 can still be used in developing and deploying directly to Azure, Appharbor, or Heroku.

What did I get out of it?

I really got into githubbing and OSSing, and really had to try hard to not over stretch myself as I had starting forking repos to try and make a few tweaks to things whilst working on the node month.

It has been extremely inspiring and has opened up so many other random tangents for me to explore in other projects at some other time. Very motivating stuff.

I’ve now got a month of half decent blog posts – I had only intended to do a total of 4 posts but including this one I’ve done 7, since I kept adding more information as it turned up and needed to split a few posts into two.

Also I’ve learned a bit about blogging; trying to do posts well in advance allowed me to build up the details once I’d discovered more whilst working on subsequent posts. For example, how Appharbor and Azure initially track master – but can be configured to track different branches. Also, debugging with Heroku only came up whilst working with packages in Heroku.

Link list

Node tutorials and references

Setting up a node development environment on Windows
Node Beginner – a great article, and I’ve also bought the associated eBooks.
nodejs.org – the official node site, the only place to go for reference

Understanding Javascript better

Execution in The Kingdom of Nouns
Object Orientation and Inheritance in Javascript

Appharbor

Appharbor and git

Heroku

Heroku toolbelt download and reference
node on Heroku

Azure

Checkout what Azure can do!

February – coming up, Samsung Smart TV App Development!

Yeah, seriously. How random is that?.. 🙂

Node.js 101: Part #5 – Packages

Following on from my recent post about doing something this year, I’m committing to doing 12 months of “101”s; posts and projects themed at begining something new (or reasonably new) to me

January is all about node, and I started with a basic intro, then cracked open a basic web server with content-type manipulation and basic routing, created a basic API, before getting stuck into some great deployment and hosting solutions

Node Packages

Up until now I’ve been working with node using the basic code I’ve written myself. What about if you want to create an application that utilises websockets? Or how about a Sinatra-inspired web framework to shortcut the routing and request handling I’ve been writing? Maybe you want to have a really easy to build website without having to write HTML with a nice look without writing any CSS? Like coffeescript? mocha? You gaddit.

Thanks to the node package manager you can easily import pre-built packages into your project to do alllll of these things and loads more. This command line tool (which used to be separate but is now a part of the node install itself) can install the packages in a ruby gem-esque/.Net nuget fashion, pulling down all the dependencies automatically.

Example usage:

npm install express -g

The packages (compiled C++ binaries, just like node itself) are pulled either into your working directory (local node_modules folder) or as a global package (with the “-g” parameter). You then reference the packages in your code using “requires”.

Or you can install everything your project needs at once by creating a package.json e.g.:

{
  "name": "basic-node-package",
  "version": "0.0.1",
  "dependencies": {
    "express": "*",
    "jade": "*",
    "stylus": "*",
    "nib": "*"
  }
}

And then call

npm install

A great intro to using these four packages can be found on the clock website

I’ve decided to write a wrapper for my basic node API using express, jade, stylus, and nib. All I’m doing is call the api and displaying the results on a basic page. The HTML is being written in jade and the css in stylus & nib. Routing is being handled by express.

app.js

var express = require('express')
  , stylus = require('stylus')
  , nib = require('nib')
  , proxy = require('./proxy')

var app = express()
function compile(str, path) {
  return stylus(str)
    .set('filename', path)
    .use(nib())
}
app.set('views', __dirname + '/views')
app.set('view engine', 'jade')
app.use(express.logger('dev'))
app.use(stylus.middleware(
  { src: __dirname + '/public'
  , compile: compile
  }
))
app.use(express.static(__dirname + '/public'))

var host = 'rposbo-basic-node-api.azurewebsites.net';

app.get('/products/:search/:key', function (req,response) {
console.log("Request handler 'products' was called");

  var requestPath = '/products/' + req.params.search + '?key=' + req.params.key;
    
  proxy.getRemoteData(host, requestPath, function(json){
    var data = JSON.parse(json);
    
    response.render('products',
        {
            title: 'Products for' + data.category,
            products: data.products,
            key: req.params.key
        }
    );
  })
});

app.get('/product/:id/:key', function (req,response) {
console.log("Request handler 'product' was called");

  var requestPath = '/product/' + req.params.id + '?key=' + req.params.key;
    
  proxy.getRemoteData(host, requestPath, function(json){
    var data = JSON.parse(json);
    
    response.render('product',
        {
            title: data.title,
            product: data
        }
    );
  })
});

app.get('/', function (req,response) {
    console.log("Request handler 'index' was called");
    response.end("Go");
});

app.listen(process.env.PORT);

So that file sets up the express, jade, and stylus references and wires up the routes for /products/ and /product/ which then make a call using my old proxy.js to the API; I can probably do all of this with a basic inline http get, but I’m just reusing it for the time being.

Notice how the route “/products/:search/:key” which would actually be something like “/products/jeans/myAp1k3Y” is referenced using req.params.search and req.params.key.

Then all I’m doing is making the API call, parsing the returned JSON and passing that parsed object to the view.

The views are written in jade and have a main shared one:
layout.jade

!!!5
html
  head
    title #{title}
    link(rel='stylesheet', href='/stylesheets/style.css')
  body
    header
      h1 basic-node-packages
    .container
      .main-content
        block content
      .sidebar
        block sidebar
    footer
      p Running on node with Express, Jade and Stylus

Then the route-specific ones:

products.jade:

extend layout
block content
  p
    each product in products
        li
            a(href='/product/' + product.id + '/' + key)
                img(src=product.image)
                p
                    =product.title

and

product.jade:

extend layout
block content
  p
    img(src=product.image)
    li= product.title
    li= product.price

The stylesheet is written in stylus & nib:

style.styl

/*
 * Import nib
 */
@import 'nib'

/*
 * Grab a custom font from Google
 */
@import url('http://fonts.googleapis.com/css?family=Quicksand')

/*
 * Nib provides a CSS reset
 */
global-reset()

/*
 * Store the main color and
 * background color as variables
 */
main-color = #fa5b4d
background-color = #faf9f0

body
  font-family 'Georgia'
  background-color background-color
  color #444

header
  font-family 'Quicksand'
  padding 50px 10px
  color #fff
  font-size 25px
  text-align center

  /*
   * Note the use of the `main-color`
   * variable and the `darken` function
   */
  background-color main-color
  border-bottom 1px solid darken(main-color, 30%)
  text-shadow 0px -1px 0px darken(main-color, 30%)

.container
  margin 50px auto
  overflow hidden

.main-content
  float left

  p
    margin-bottom 20px

  li
    width:290
    float:left

p
  line-height 1.8

footer
  margin 50px auto
  border-top 1px dotted #ccc
  padding-top 5px
  font-size 13px

And this is compiled into browser-agnostic css upon compilation of the app.

The other files used:

proxy.js:

var http = require('http');

function getRemoteData(host, requestPath, callback){
  
    var options = {
        host: host,
        port: 80,
        path: requestPath
    };
 
    var buffer = '';
    var request = http.get(options, function(result){
        result.setEncoding('utf8');

        result.on('data', function(chunk){
            buffer += chunk;
        });

        result.on('end', function(){
            callback(buffer);
        });
    });

    request.on('error', function(e){console.log('error from proxy call: ' + e.message)});
    request.end();
};
exports.getRemoteData = getRemoteData;

package.json

{
  "name": "basic-node-package",
  "version": "0.0.1",
  "dependencies": {
    "express": "*",
    "jade": "*",
    "stylus": "*",
    "nib": "*"
  }
}

web.config

<configuration>
    <system.web>
        <compilation batch="false" />
    </system.web>
    <system.webServer>
        <handlers>
            <add name="iisnode" path="app.js" verb="*" modules="iisnode" />
        </handlers>
        <iisnode loggingEnabled="false" />

        <rewrite>
            <rules>
                <rule name="myapp">
                    <match url="/*" />
                    <action type="Rewrite" url="app.js" />
                </rule>
            </rules>
        </rewrite>
    </system.webServer>
</configuration>

All of these files are, as usual, on Github

Deployment with Packages

Something worth bearing in mind is that deploying something which includes packages and the result of packages (e.g. minified js or css from styl) requires all of these artifacts to be added into your git repo before deployment to certain hosts such as Appharbor and Azure; Heroku will actually run an npm install as part of the deployment step, I believe, and also compile the .styl into .css, unlike Azure/Appharbor.

The files above give a very basic web interface to the /products/ and /product/ routes:
asos-jade-products-1

asos-jade-product-1

Coming up

Web-based node development and deployment!