The Art of I/O (2nd Session of 4)
A magical introduction to input and output signals
Previous Session | Course Home | Toggle Notes Mode | Watch Video Presentation | http://ioschool.is | Next Session
Course Recap
In our last session, we touched on
- functions (accept input, return output, maybe do effects)
- closures (functions that 'close over' variables)
- callbacks (functions that are 'called back' later)
- modules (exported code we can require in other code)
In this session, we'll dive deeper into the above and touch on
- events
- streams
We'll culminate with a fun cat app.
Hello Server
// hello-server.js
var http = require('http') // built-in module
function handler (req, res) {
res.end("hello world!")
}
var server = http.createServer(handler)
server.listen(5000)
Start with node hello-server.js
.
HTTP Magic
Request In, Response Out.
HTTP is a simple message passing protocol: the "client" sends a request message to the "server", the "server" sends a response message back to the "client."
Try being an HTTP client with your web browser, curl
, or even netcat
.
Random Cat Face
npm install cat-ascii-faces
// cat-face.js
var http = require('http') // built-in module
var catFaces = require('cat-ascii-faces') // npmjs.org module
function handler (req, res) {
res.end(catFaces())
}
var server = http.createServer(handler)
server.listen(5000)
Start with node cat-face.js
.
Random Cat API
npm install cat-names
// cat-api.js
var http = require('http') // built-in module
var catFaces = require('cat-ascii-faces') // npmjs.org module
var catNames = require('cat-names').random // npmjs.org module
function handler (req, res) {
res.end(JSON.stringify({
face: catFaces(),
name: catNames(),
}, null, 2))
}
http.createServer(handler).listen(5000)
Start with node cat-api.js
.
Random Cat Images
npm install request
// cat-images.js
// we want to write a module that
// fetches a url to a random cat image
// and returns it via a callback
var request = require('request') // npmjs.org module
function catImages (callback) {
var url = "http://random.cat/meow"
request(url, function (err, res) {
callback(err, res.body)
})
}
module.exports = catImages
Import with require('./cat-images')
.
// cat-api.js
var http = require('http') // built-in module
var catFaces = require('cat-ascii-faces') // npmjs.org module
var catNames = require('cat-names').random // npmjs.org module
var catImages = require('./cat-images') // our shiny module
function handler (req, res) {
catImages(function (err, catImage) {
res.end(JSON.stringify({
face: catFaces(),
name: catNames(),
image: catImage,
}, null, 2))
}))
}
http.createServer(handler).listen(5000)
Start with node cat-api.js
.
Let's export our Cat API as a module, running the server if called directly.
// cat-api.js
// ...
module.exports = handler
if (!module.parent) {
http.createServer(handler).listen(5000)
}
Start with node cat-api.js
.
Import with require('./cat-api.js')
.
Cat Server
Now let's write a higher-level handler that uses our ./cat-api
handler when we request '/meow'.
// cat-server.js
var http = require('http')
var catApi = require('./cat-api')
function handler (req, res) {
if (req.url === "/meow") {
catApi(req, res)
} else {
res.writeHead(404, 'not found')
res.end()
}
}
http.createServer(handler).listen(5000)
Cat HTML
Now let's use our cat server to serve some HTML.
// cat-server.js
var http = require('http')
var fs = require('fs')
var catApi = require('./cat-api')
function handler (req, res) {
if (req.url === "/meow") {
catApi(req, res)
} else if (req.url === "/") {
fs.createReadStream("./cat-index.html").pipe(res)
} else {
res.writeHead(404, 'not found')
res.end()
}
}
http.createServer(handler).listen(5000)
Cat HTML
Now let's write that HTML.
<!-- cat-index.html -->
<!DOCTYPE html>
<html>
<head>
<title>(=^.^=)</title>
<link href="./styles.css" rel="stylesheet" />
</head>
<body>
<main>
<h1>Meow :3</h1>
<div class="cats"></div>
</main>
<script src="./scripts.js"></script>
</body>
</html>
Styles
Let's serve up some './styles.css'
// cat-server.js
// ...
function handler (req, res) {
// ...
} else if (req.url === "/styles.css") {
fs.createReadStream("./cat-styles.css").pipe(res)
} else {
// ...
cat-styles.css
main {
text-align: center;
}
h1 {
font-size: 100px;
}
Scripts
Let's serve up some './scripts.js'
// cat-server.js
// ...
function handler (req, res) {
// ...
} else if (req.url === "/scripts.js") {
fs.createReadStream("./cat-scripts.js").pipe(res)
} else {
// ...
// cat-scripts.js
console.log("eomay")
Browserify Magic
browserify lets you require('modules') in the browser.
npm install browserify
// cat-server.js
// ...
var browserify = require('browserify')
// ...
function handler (req, res) {
// ...
} else if (req.url === "/scripts.js") {
browserify("./cat-scripts.js").bundle().pipe(res)
} else {
// ...
// cat-scripts.js
console.log(require('cat-ascii-faces')())
Request a cat in the browser!
npm install xhr
// cat-scripts.js
var xhr = require('xhr')
function getCat (callback) {
xhr("/meow", function (err, res) {
callback(err, JSON.parse(res.body))
})
}
getCat(function (err, cat) {
if (!err) console.log(cat)
})
Display a cat in the browser!
npm install domquery
// cat-scripts.js -------------------------
// ...
var dom = require('domquery')
function addCat (cat) {
var catView =
"<div class='cat'>" +
"<h2>{face}</h2>" +
"<h3>{name}</h3>" +
"<img src='{image}'/>" +
"</div>"
dom('.cats').add(catView, cat)
}
// ...
getCat(function (err, cat) {
if (!err) addCat(cat)
})
Cat Button
Let's add a cat button to our html.
<!-- cat-index.html -->
<main>
<h1>Meow :3</h1>
<div class="cats"></div>
<button class="add-cat">Add Cat!</button>
</main>
// cat-scripts.js
// ...
dom('.add-cat').on('click', function (ev) {
console.log(ev)
})
More Cats
Let's put it all together, add a cat when we click the button!
// cat-scripts.js
// ...
dom('.add-cat').on('click', function (ev) {
getCat(function (err, cat) {
if (!err) addCat(cat)
})
})
Hey look, a sweet cat app! :3
Continuing the Magic
NodeSchool
- javascripting: Javascript workshop
- learnyounode: Async I/O workshop
- async-you: Advanced async workshop
- browserify-adventure: Browserify workshop