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:

  1. core modules

  2. relative .js file path

  3. relative folder path with index.js

  4. local node_modules folder

  5. 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

testing is usually done with

jasmine or mocha

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!

Usual suspects:

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

Made with Slides.com