Vitor Fernandes
github.com/vmlf01
https://github.com/vmlf01/nodejs-presentation
Summary
-
the motive behind node.js
-
node architecture
-
the event loop
-
npm & CommonJS modules
-
LIVE CODING: a simple API server
-
unit testing
The Motive
Behind
Node.js
Created 2009 by Ryan Dahl
why?
because I/O is slow
Title Text
Grace Hopper, a pioneer, explains:
so the idea is:
I/O needs to be done differently
node.js uses an
instead of blocking
event loop
Node
Architecture
-
Server-side javascript
-
Written in C, C++, Javascript
-
Built on Google V8 engine
-
Evented, non-blocking I/O
-
CommonJS module system
Title Text
Subtitle
Title Text
Subtitle
The
Event
Loop
JavaScript is designed to be used with an event loop
-
anonymous functions
-
closures
-
event callbacks
Philip Roberts: What the heck is the event loop anyway?
must see:
The V8 engine has a
Call Stack
and a
Heap
everything else
is provided by the host,
be it the
browser
or
Node.js
Getting
Started
You can download and install Node.js from https://nodejs.org/
When installed, you get:
-
a command line interpreter (node)
-
a package manager (npm)
Try it out:
create an index.js file with:
console.log('Hello World');
and run it with:
$ node index.js
node will execute the script inside index.js and exit
that's because
there was nothing else to do!
change index.js to:
setTimeout(function () {
console.log('Hello World');
}, 5000);
and run it again:
$ node index.js
now the application will only terminate after the setTimeout callback is executed
Node
Modules
Node.js uses the CommonJS
module system
In Node js,
every source file is a module
everything inside is private, except what you export using module.exports
or
exports
a module acts as a closure
to import a module, use
require('module')
modules are loaded once and
cached, acting like singletons
split hello world into 2 files:
- index.js
- hello.js
// hello.js
module.exports.sayHello = function (name) {
console.log('Hello ' + name);
};
// index.js
var hello = require('./hello');
hello.sayHello('World');
$ node index.js
Node.js uses specific rules to locate the required module
(incomplete) rule of thumb:
-
core modules
-
relative .js file path
-
relative folder path with index.js
-
local node_modules folder
-
global node_modules folder
main core modules
-
fs
-
path
-
http
-
net
main core globals
-
require
-
module
-
process
-
console
-
setTimeout
Let's
get
cracking...
what are we going to build?
optimus primes
create a service that will tell:
-
is N a prime number?
-
how many primes are there in the first N positive integers?
a node "project" is just a folder with a
metadata file
package.json
npm
there's a module for that!
npm is a command line utility to manage
all your application dependencies
and more!
npm commands to remember
$ npm init
$ npm install
$ npm install -g <package>
$ npm install --save <package>
$ npm install --save-dev <package>
$ npm start
$ npm test
$ npm run <script>
let's use npm init to create our project
after npm init is finished, you will get a
package.json file with your project information
most important attributes are:
"main": points to your app main entry file
"scripts": contains commands you can execute with npm run
let's create a folder structure like this:
describe() creates a test group
it() creates a test case
after it passes all the tests,
try to optimize
ideally, you write a bit of test, implement the minimum amount of code to make it pass and repeat
RED
GREEN
REFACTOR
"Ada improves code safety and maintainability by using the compiler
to find errors in favor of runtime errors."
and yet...
test code is just code
and it's node.js code
so we are learning something
consider it part of the sample
:)
install the modules we are going to need
$ npm install mocha --save-dev
$ npm install should --save-dev
implement the primes.js module
and
!!! LIVE CODING !!!
primes.js module test cases:
require('should');
var primes = require('../src/primes.js');
describe('primes', function () {
it('should export a member function isPrime');
it('should export a member function countPrimes');
describe('isPrime', function () {
it('should return false if N is less than 2');
it('should return true if N is only divisible by 1 and itself');
});
describe('countPrimes', function () {
it('should return 0 if N is less than 2');
it('should return number of primes between 1 and N inclusive');
});
});
Coffee
Break
1 hour mark (hopefully)
Creating
API
Service
basic HTTP server
// require node 'http' core module
var http = require('http');
// read port from environment variable 'PORT' or use '3000' as default
var port = process.env.PORT || 3000;
// create an http server and set the request handler
var server = http.createServer(function (req, res) {
res.writeHead(200, { "Content-Type": "application/json" });
res.write(JSON.stringify({ msg: 'Hello', requestPath: req.url }));
res.end();
});
// start up server on all IP interfaces on specified port
server.listen(port, '0.0.0.0', function () {
console.log('App server is running on http://0.0.0.0:' + port);
});
however...
remember the mantra
there's a module for that!
let's use express
$ npm install express --save
quick express overview
express uses a middleware
pipeline architecture
incoming requests go through a series of steps
that process the request and can terminate
or hand off the request to the next step in the pipeline
// require express module
var express = require('express');
// create a new express 'application'
var app = express();
// add middleware to the pipeline
app.use(function (req, res, next) {
console.log('Incoming request for ' + req.url);
next();
});
// add a route handler
app.get('*', function (req, res) {
res.send('Hello World!');
});
// start server listening on port 3000
app.listen(3000, function () {
console.log('Example app listening on http://localhost:3000');
});
to test our API endpoints, we are going to use
Super-agent driven library for testing
node.js HTTP servers using a fluent API
supertest
var request = require('supertest');
var app = require('../src/app');
describe('primes api', function () {
describe('/isprime', function () {
it('should return 200 if request is valid');
it('should return 400 if request is invalid');
it('should return result object in body');
});
describe('/count', function () {
it('should return 200 if request is valid');
it('should return 400 if request is invalid');
it('should return result object in body');
});
});
API basic routes tests
let's create our API pipeline
// require express module
var express = require('express');
// require our primes module
var primes = require('./primes');
// create a new express 'application'
var app = express();
// add middleware to the pipeline
app.use(function (req, res, next) {
console.log('Incoming request for ' + req.url);
next();
});
// add route handlers
app.get('/isprime/:number', handleIsPrime);
app.get('/count/:number', handlePrimeCount);
// export the express app
module.exports = app;
and use our primes module to handle requests
// require our primes module
var primes = require('./primes');
function handleIsPrime(req, res) {
var number = Number(req.params.number);
if (isNaN(number)) {
res.status(400).end();
}
else {
res.status(200).send({ result: primes.isPrime(number) });
}
}
function handlePrimeCount(req, res) {
var number = Number(req.params.number);
if (isNaN(number)) {
res.status(400).end();
}
else {
res.status(200).send({ result: primes.countPrimes(number) });
}
}
bonus points: code coverage
istanbul
# install istanbul package
$ npm install --save-dev istanbul
# on linux we can just use "_mocha"
$ istanbul --include-all-sources cover _mocha
# on windows, we need to specify the path to the "mocha" script
$ istanbul --include-all-sources cover node_modules/mocha/bin/_mocha
Final
Thoughts
when to use Node.js:
-
Chat/Messaging
-
Real-Time Applications
-
Intelligent Proxies
-
High Concurrency Applications
-
Communication Hubs
-
Coordinators
flagship cases:
bad stuff:
-
CPU intensive tasks
-
Breaking changes in non-core modules
-
Documentation could be friendlier
surprise:
run and compare
primes.js and primes.c
execution times
Node
School
NodeSchool
NodeSchool is an open source project run by volunteers with two goals: to create high quality programming curriculum and to host community learning events.
In Portugal
require('lx') meetup organizes
regular monthly NodeSchool events
SINFO also organizes some NodeSchool
events once in a while
NodeSchool International Day
Node.js - JavaScript everywhere
By Vitor Fernandes
Node.js - JavaScript everywhere
Get an overview of what Node.js is and how you can use it. We will go over the Node.js architecture, the development eco-system and a brief live-coding session on how to write and test your apps.
- 1,138