SIGAPP Meeting 13

03 November 2015

 

Node.js

What is Node.js?

  • Its javascript outside the browser
  • It is mainly used for creating web applications
  • However, it is general purpose, it can do everything Java, Python, C can

What is Node.js used for?

  • Writing an API Server (like the dinning court API)
  • Writing a HTTP Server (for hosting your html/css files)
  • Web scraping, grabbing information from the web (like the Purdue Directory)

Installing Node.js

curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.29.0/install.sh | bash

nvm install 4.0

nvm use 4.0

Quick Node test

Lets see if node installed correctly

Our first Node program

Open a file and read its contents

// this is like an import statement in java
var fs = require('fs');

// this is the function that is called when the file is opened
function onFileOpenedFunction(err,data){
	if(err){
		return console.log(err);
	}
	names = data.split('\n');
	for(var i = 0; i<names.length; i++){
		console.log(names[i]);
	}
}

function openAndPrintNames(filename){
	fs.readFile(filename, 'utf8', onFileOpenedFunction);
}

openAndPrintNames('names.txt');

run this with the command `node fileOpen.js`

Mike
Tylor
Kyle
Jeff
Jordan
Another Mike

fileOpen.js

names.txt

Our first Node program

Version 2.0

// this is like an import statement in java
var fs = require('fs');

function openAndPrintNames(filename){
	fs.readFile(filename, 'utf8', function(err, data){
		if(err){
			console.log('err');
		}
		names = data.split('\n');
		names.forEach(function(name){
			console.log(name);
		});
	});
}
openAndPrintNames('names.txt');

run this with the command `node fileOpenv2.js`

Mike
Tylor
Kyle
Jeff
Jordan
Another Mike

fileOpenv2.js

names.txt

Take Aways from our Program

  • Lots of node functions take callbacks
  • callbacks in the form of open(callbackFunction);
  • These callbacks can anonymous or passed it like a variable
// using anonymous callback
open(function(err,data){
});


function onOpen(err,data){
}

//using named calledback
open(onOpen);

Using NPM

  • Node comes with a package manager for managing libraries called npm (Node Package Manager)
  • Each node app has an associated package.json
  • The package.json is a config file which tells npm what libraries you will use in your app
  • create this package.json by doing a `npm init`
  • Go to https://www.npmjs.com/ to search for packages
npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help json` for definitive documentation on these fields
and exactly what they do.

Use `npm install <pkg> --save` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
name: (sigapp13) 
version: (1.0.0) 
description: an tutorial on node
entry point: (index.js) 
test command: 
git repository: 
keywords: 
author: Kyle Potts
license: (ISC) 
About to write to /home/kyle/dev/node/sigapp13/package.json:

{
  "name": "sigapp13",
  "version": "1.0.0",
  "description": "an tutorial on node",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Kyle Potts",
  "license": "ISC"
}


Is this ok? (yes) yes

Package.json

{
  "name": "sigapp13",
  "version": "1.0.0",
  "description": "an tutorial on node",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Kyle Potts",
  "license": "ISC"
}

Installing a library

  • Lets install the request package https://www.npmjs.com/package/request
  • this lets us do simple HTTP Requests (GET,POST,PUT,DELETE)
  • npm install --save request
    • the --save puts it in our package json
    • libraries are installed in a node_modules folder
➜  sigapp13  npm install --save request
sigapp13@1.0.0 /home/kyle/dev/node/sigapp13
└─┬ request@2.65.0 
  ├── aws-sign2@0.6.0 
  ├─┬ bl@1.0.0 
  │ └─┬ readable-stream@2.0.4 
  │   ├── core-util-is@1.0.1 
  │   ├── inherits@2.0.1 
  │   ├── isarray@0.0.1 
  │   ├── process-nextick-args@1.0.3 
  │   ├── string_decoder@0.10.31 
  │   └── util-deprecate@1.0.2 
  ├── caseless@0.11.0 
  ├─┬ combined-stream@1.0.5 
  │ └── delayed-stream@1.0.0 
  ├── extend@3.0.0 
  ├── forever-agent@0.6.1 
  ├─┬ form-data@1.0.0-rc3 
  │ └── async@1.5.0 
  ├─┬ har-validator@2.0.2 
  │ ├─┬ chalk@1.1.1 
  │ │ ├── ansi-styles@2.1.0 
  │ │ ├── escape-string-regexp@1.0.3 
  │ │ ├─┬ has-ansi@2.0.0 
  │ │ │ └── ansi-regex@2.0.0 
  │ │ ├── strip-ansi@3.0.0 
  │ │ └── supports-color@2.0.0 
  │ ├─┬ commander@2.9.0 
  │ │ └── graceful-readlink@1.0.1 
  │ ├─┬ is-my-json-valid@2.12.2 
  │ │ ├── generate-function@2.0.0 
  │ │ ├─┬ generate-object-property@1.2.0 
  │ │ │ └── is-property@1.0.2 
  │ │ ├── jsonpointer@2.0.0 
  │ │ └── xtend@4.0.1 
  │ └─┬ pinkie-promise@1.0.0 
  │   └── pinkie@1.0.0 
  ├─┬ hawk@3.1.0 
  │ ├── boom@2.10.1 
  │ ├── cryptiles@2.0.5 
  │ ├── hoek@2.16.3 
  │ └── sntp@1.0.9 
  ├─┬ http-signature@0.11.0 
  │ ├── asn1@0.1.11 
  │ ├── assert-plus@0.1.5 
  │ └── ctype@0.5.3 
  ├── isstream@0.1.2 
  ├── json-stringify-safe@5.0.1 
  ├─┬ mime-types@2.1.7 
  │ └── mime-db@1.19.0 
  ├── node-uuid@1.4.3 
  ├── oauth-sign@0.8.0 
  ├── qs@5.2.0 
  ├── stringstream@0.0.5 
  ├── tough-cookie@2.2.0 
  └── tunnel-agent@0.4.1 

npm WARN EPACKAGEJSON sigapp13@1.0.0 No repository field.

Node Modules

  • You should now have node_modules folder
  • this contains all the package you install and their packages they depend on
  • see how many package the request package depends on
➜  sigapp13  ls -l node_modules 
total 216
drwxr-xr-x 2 kyle users 4096 Nov  3 13:28 ansi-regex
drwxr-xr-x 2 kyle users 4096 Nov  3 13:28 ansi-styles
drwxr-xr-x 4 kyle users 4096 Nov  3 13:28 asn1
drwxr-xr-x 2 kyle users 4096 Nov  3 13:28 assert-plus
drwxr-xr-x 4 kyle users 4096 Nov  3 13:28 async
drwxr-xr-x 2 kyle users 4096 Nov  3 13:28 aws-sign2
drwxr-xr-x 3 kyle users 4096 Nov  3 13:28 bl
drwxr-xr-x 5 kyle users 4096 Nov  3 13:28 boom
drwxr-xr-x 2 kyle users 4096 Nov  3 13:28 caseless
drwxr-xr-x 2 kyle users 4096 Nov  3 13:28 chalk
drwxr-xr-x 3 kyle users 4096 Nov  3 13:28 combined-stream
drwxr-xr-x 2 kyle users 4096 Nov  3 13:28 commander
drwxr-xr-x 3 kyle users 4096 Nov  3 13:28 core-util-is
drwxr-xr-x 4 kyle users 4096 Nov  3 13:28 cryptiles
drwxr-xr-x 4 kyle users 4096 Nov  3 13:28 ctype
drwxr-xr-x 3 kyle users 4096 Nov  3 13:28 delayed-stream
drwxr-xr-x 2 kyle users 4096 Nov  3 13:28 escape-string-regexp
drwxr-xr-x 2 kyle users 4096 Nov  3 13:28 extend
drwxr-xr-x 2 kyle users 4096 Nov  3 13:28 forever-agent
drwxr-xr-x 3 kyle users 4096 Nov  3 13:28 form-data
drwxr-xr-x 2 kyle users 4096 Nov  3 13:28 generate-function
drwxr-xr-x 2 kyle users 4096 Nov  3 13:28 generate-object-property
drwxr-xr-x 2 kyle users 4096 Nov  3 13:28 graceful-readlink
drwxr-xr-x 4 kyle users 4096 Nov  3 13:28 har-validator
drwxr-xr-x 2 kyle users 4096 Nov  3 13:28 has-ansi
drwxr-xr-x 6 kyle users 4096 Nov  3 13:28 hawk
drwxr-xr-x 5 kyle users 4096 Nov  3 13:28 hoek
drwxr-xr-x 3 kyle users 4096 Nov  3 13:28 http-signature
drwxr-xr-x 2 kyle users 4096 Nov  3 13:28 inherits
drwxr-xr-x 3 kyle users 4096 Nov  3 13:28 isarray
drwxr-xr-x 3 kyle users 4096 Nov  3 13:28 is-my-json-valid
drwxr-xr-x 2 kyle users 4096 Nov  3 13:28 is-property
drwxr-xr-x 2 kyle users 4096 Nov  3 13:28 isstream
drwxr-xr-x 2 kyle users 4096 Nov  3 13:28 jsonpointer
drwxr-xr-x 3 kyle users 4096 Nov  3 13:28 json-stringify-safe
drwxr-xr-x 2 kyle users 4096 Nov  3 13:28 mime-db
drwxr-xr-x 2 kyle users 4096 Nov  3 13:28 mime-types
drwxr-xr-x 5 kyle users 4096 Nov  3 13:28 node-uuid
drwxr-xr-x 2 kyle users 4096 Nov  3 13:28 oauth-sign
drwxr-xr-x 2 kyle users 4096 Nov  3 13:28 pinkie
drwxr-xr-x 2 kyle users 4096 Nov  3 13:28 pinkie-promise
drwxr-xr-x 2 kyle users 4096 Nov  3 13:28 process-nextick-args
drwxr-xr-x 5 kyle users 4096 Nov  3 13:28 qs
drwxr-xr-x 4 kyle users 4096 Nov  3 13:28 readable-stream
drwxr-xr-x 3 kyle users 4096 Nov  3 13:28 request
drwxr-xr-x 5 kyle users 4096 Nov  3 13:28 sntp
drwxr-xr-x 2 kyle users 4096 Nov  3 13:28 string_decoder
drwxr-xr-x 2 kyle users 4096 Nov  3 13:28 stringstream
drwxr-xr-x 2 kyle users 4096 Nov  3 13:28 strip-ansi
drwxr-xr-x 2 kyle users 4096 Nov  3 13:28 supports-color
drwxr-xr-x 3 kyle users 4096 Nov  3 13:28 tough-cookie
drwxr-xr-x 2 kyle users 4096 Nov  3 13:28 tunnel-agent
drwxr-xr-x 2 kyle users 4096 Nov  3 13:28 util-deprecate
drwxr-xr-x 2 kyle users 4096 Nov  3 13:28 xtend

Updated Package.json

{
  "name": "sigapp13",
  "version": "1.0.0",
  "description": "an tutorial on node",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Kyle Potts",
  "license": "ISC",
  "dependencies": {
    "request": "^2.65.0"
  }
}

Lets Use that Request Package

  • In this example we use the Purdue Dining Court API
  • We use the Request Library to make a GET Request to the API and get the menus.
  • We then turn it into a JSON object and print out the information
  • Create file courtAPI.js
  • run the file as `node courtAPI.js`
var request = require('request');

function handleMeal(meal){
  console.log('\tMeal -- ' + meal.Name);
  meal.Stations.forEach(handleStation);
}

function handleStation(station){
  console.log('\t\t Station -- ' + station.Name);
  station.Items.forEach(handleStationItem);
  console.log('\n');
}

function handleStationItem(item){
  console.log('\t\t\t ' + item.Name);
}

function handleAPIResponse(resp){
  console.log('Court --' + resp.Location);
  resp.Meals.forEach(handleMeal);
}


function callAPI(courtName){
  request('http://api.hfs.purdue.edu/menus/v2/locations/' + courtName + '/11-03-2015', function (error, response, body) {
    if (!error && response.statusCode == 200) {
      var respObj = JSON.parse(body); 
      handleAPIResponse(respObj);
    }
  });
}

function getFood(){
  var courtNames = ['ford', 'wiley', 'earhart', 'windsor', 'hillenbrand'];
  courtNames.forEach(function(name){
    callAPI(name);
  });
}

getFood();

Courts API Version 2

  • Named functions are not super common in js
  • most functions are anonymous 
  • lets rewrite the app with anonymous functions
var request = require('request');

function callAPI(courtName){
  request('http://api.hfs.purdue.edu/menus/v2/locations/' + courtName + '/11-03-2015', function (error, response, body) {
    if (!error && response.statusCode == 200) {
      var respObj = JSON.parse(body);
      respObj.Meals.forEach(function(meal){
        console.log('\tMeal -- ' + meal.Name);
        meal.Stations.forEach(function(station){
          console.log('\t\t Station -- ' + station.Name);
          station.Items.forEach(function(item){
              console.log('\t\t\t ' + item.Name);
          });
          console.log('\n');
        });
      });
    }
  });
}

function getFood(){
  var courtNames = ['ford', 'wiley', 'earhart', 'windsor', 'hillenbrand'];
  courtNames.forEach(function(name){
    callAPI(name);
  });
}

getFood();
  • Much less boilerplate, easier to read
  • This can get ugly quick though (callback hell)

Another Example - Simple HTTP

  • Node has a built in HTTP Library
  • Requires no npm install (cool!)
  • Very simple
var http = require('http');

http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World\n');
}).listen(8080, "localhost");

console.log('Server running at http://localhost:8080/');

`node server.js`

Visit http://localhost:8080

server.js

HTTP File Server

  • Think back to when we made our chat app
  • we used python  `python -m SimpleHTTPServer` to server the html page we created
  • Well instead of python we can use Node to host our files
<html>
  <head>
    <title>Cool stuff </title>
  </head>
  <body>
    <h1>Hello World </h1>
  </body>
</html>
var fs = require('fs'),
    http = require('http');

http.createServer(function (req, res) {
  fs.readFile(__dirname + req.url, function (err,data) {
    if (err) {
      res.writeHead(404);
      res.end(JSON.stringify(err));
      return;
    }
    res.writeHead(200);
    res.end(data);
  });
}).listen(8080);

index.html

 

fileServer.js

Where next?

Made with Slides.com