NodeJs
Quoting the Node.js website
See also Wikipedia node.js, here is the Node.js API. I also like this book (German only) Node.js Das umfassende Handbuch (German).
Node.js getting started
You may start the Node.js interactive mode by running node.exe. It is called REPL.
> console.log('Test');
Test
undefined
Ignore the word undefined in the output it is just there to show you the return value of the console.log function, which is not set. It will appear everywhere in the interactive mode, but I will skip it from now on.
Assign a value to a variable
> console.log(x);
Hello World
Interactive mode commands
.clear
.exit
.help
.load
.save
Normally you start your code like this:
Node.js IDE
The easiest way to get started right away is probably to get an account at Cloud9 and develop within your browser on their cloud IDE. There is also the Eclipse plugin Nodeclipse for Node.js. Another way seems to be to install it via npm (part of the Node.js installation), but that did not bring it into my Eclipse (is it supposed to?)
# npm install -g express-generator
# npm install -g express
Once it works you can add in Eclipse a new Node.js Project (via New Project).
Modules
Node.js comes with a lot of modules you use for your project. You can load them with the require statement and install new ones with the npm command. Often used Node.js modules
Write your own module
Place this into a file called MyFirstModule.js
return 'Hello ' + x;
};
Now once you require this file, it will load your module and make everything with exports available
console.log(foo.sayHello('World'));
Within your module you can get some information about it
console.log(module.filename);
console.log(module.loaded);
console.log(module.parent);
console.log(require.main.filename);
Node.js will search your module first in the folder node_modules in the current directory, then in the directory above the current directory, etc., then in the folders listed in the NODE_PATH variable and then in your home directory.
If you require a folder and not a file, the file package.json is searched there.
Automated restarts on code changes
Your program has to be stopped and restarted every time you can something in the code. Let this happen automatically
# nodemon myFirstNodejsCode.js
Unit testing
assert.ok(42 < 45);
assert.ok(42 < 5);
console.log('Done');
Events
Node.js works a lot with callback functions being called, triggered by events. Normally you just provide the callback function and the events are handled by the module you are dealing with, but you can also do it yourself
console.log('dring');
}
var callback2 = function() {
console.log('dingdingding');
}
var events = require('events');
var ee=new events.EventEmitter();
ee.once('ringTheBell', callback1);
ee.on ('ringTheBell', callback2);
ee.emit('ringTheBell');
ee.emit('ringTheBell');
ee.removeListener('ringTheBell', callback2);
ee.emit('ringTheBell');
Output:
dingdingding
dingdingding
Timers
console.log('s: ' + s);
console.log('n: ' + n);
}
var myStopItFunction = function(inter) {
// stop a running timeout
clearTimeout(inter);
}
// start this every 3 seconds
var interval=setInterval(myStopWatchCallBackFunction, 3000, 'Hello World', 42);
// start this once after 10 seconds
var timeout =setTimeout(myStopItFunction, 10000, interval);
Utility
Helper method, logging, String formating, type testing, show object details with inspect, inheriting via
Logger
Callback hell
async
IO
Console
console.log('Hello World');
console.timeEnd('myStopWatch');
myStopWatch: 2ms
Path
You should use path and path.join or path.sep to build a path to a file to respect the separator on the system Node.js is running.
Reading and writing Files
This uses the fs module to read a file. Once the data has been read it is passed to the function you provided. Please note that it is very likely that the first output will be the word Done before the actual file content is outputted, because the fs module will need some time to read the file.
var myFile = "c:temptg.txt";
// overwrite the file with a new line
fs.writeFile(myFile, "Helllo world", function (err, data) {
if(err) {throw err};
// if we reach here, file has been overwritten, append some data now
fs.appendFile(myFile, " and hello Moon", function(err, data) {
if(err) {throw err;}
// if we reach here, file has an extra line, now read the whole file again
fs.readFile(myFile, function (err, content) {
if(err) {throw err;}
console.log(content.toString());
fs.close();
});
});
});
console.log('Done');
Streams
Streams are used in several parts of Node.js.
// the stream we read from (a file)
var myReadStream=fs.createReadStream('c:temptg.txt' ); // fs.createReadStream('c:temptg.txt', { encoding: 'utf-8' } );
// the stream we write to
var myWriteStream=fs.createWriteStream('c:temptg2.txt');
// the stream we write to (standard output)
//var myWriteStream=process.stdout;
// file opened
myReadStream.on("open", function(fd) {
console.log('Event Open');
// if you set this the data event will get a human readable string
//myReadStream.setEncoding('utf-8');
});
// data comes in
myReadStream.on("data", function(data) {
console.log('Event Data!');
// if the receiver is busy you might be nice and pause sending more data
if(!myWriteStream.write(data)) {
console.log('Write stream is full');
myReadStream.pause();
}
});
// the receiver is ready to get more data
myWriteStream.on("drain", function() {
console.log("Write stream is no longer full");
myReadStream.resume();
});
// stream closed
myReadStream.on("end", function() {
console.log("End!");
});
console.log('Done.');
Instead of manually copying the data from one stream into the next one you may also use a pipe to connect them
myReadStream.pipe(myWriteStream);
Streams2
Why streams2 is better than streams.
Network
Webserver and Client
Being able to program a webserver and webclient with only few lines of code is one of the strengths of Node.js
http.createServer().listen(8123, '127.0.0.1');
console.log('Now connect to http://127.0.0.1:8123');
This is already a running webserver, even though it does not return any data so a client will wait forever. Let's change this. We pass a function to the createServer method, which will be started whenever somebody connects to our server with a request. The function gets the request and the response which will be send. We change the response to really return something
http.createServer(function (request, response) {
response.writeHeader(200, {'content-type': 'text/plain; charset=utf-8' });
response.write('Hello ');
response.write('everybody ');
response.end(' out there!');
}).listen(8123, '127.0.0.1');
console.log('Now connect to http://127.0.0.1:8123');
The same thing but showing more what it is happening in the background
var server=new http.Server();
server.addListener('request', function(request, response) {
response.statusCode=200;
response.setHeader('content-type', 'text/plain');
response.end('Hello everybody out there!');
});
server.listen(8123, '127.0.0.1');
console.log('Now connect to http://127.0.0.1:8123');
Please note that your function is only called in the event of somebody connects to the server with a request. Otherwise your code just does nothing. This is a main principal in Node.js. Do define what function to call in an event and the rest just happens.
If your client is a browser, sending HTML is nicer
http.createServer(function (request, response) {
response.writeHeader(200, {'content-type': 'text/html; charset=utf-8' });
var myBody='<html>' +
'<head><title>Hello World</title></head>' +
'<body>' +
'<h1>Greeting</h1>' +
'Hello World' +
'</body>' +
'</html>';
response.end(myBody); // if you only have one response you can pass it to the end method, no need for write
}).listen(8123, '127.0.0.1');
console.log('Now connect to http://127.0.0.1:8123');
Request
What is coming from the client to you. For example during a file upload this might be big und split into different chunks.
http.createServer(function (request, response) {
// collect all the requests
var reqData="";
// new request
request.on('data', function(data) {
reqData=reqData+data.toString();
});
// we got them all, now return it
request.on('end', function() {
response.writeHeader(200, {'content-type': 'text/plain; charset=utf-8' });
response.write('We got this request: ');
response.write(reqData);
response.end();
});
}).listen(8123, '127.0.0.1');
console.log('Now connect to http://127.0.0.1:8123');
HTTP Client
Do no longer use
it is deprecated!
Simple example which also checks for http client request exceptions
// build the request
var myRequest=http.request('http://www.tgunkel.de/index.de.php', function(response) {
var myServerData="";
response.on('data', function(data) {
console.log('Got new data from server: ');
myServerData=myServerData+data;
})
response.on('end', function () {
console.log("This is the result");
console.log(myServerData);
});
});
// catch http client request exceptions, e.g. getaddrinfo ENOTFOUND
myRequest.on('error', function(err) {
console.log("We did hit an error" + err);
});
myRequest.end(); // this will actually send the request to the server
console.log('Done.');
You can also provide more options than just the URL
host: 'www.tgunkel.de',
port: '80',
method: 'GET',
path: '/index.de.php',
headers: { 'accept': 'text/html' }
}
var myRequest=http.request(myOptions, function(response) {
...
});
This way you can even use an http proxy:
host: 'myproxy.example.com', // proxy host
port: '8080', // proxy port
method: 'GET',
path: 'http://www.tgunkel.de/index.de.php', // full path here
headers: { Host: 'www.tgunkel.de' } // repeat the true hostname you want to go to again here
}
// build the request
var myRequest=http.request(myOptions, function(response) {
...
Shorter version for GET requests which also does not need a call to request.end()
response.on('data', function(data) {
console.log('Got new data from server: ');
console.log(data.toString());
})
});
You can also get only the request object and add an response callback method afterwards.
var myRequest=http.request(myOptions);
myRequest.on('response', function(response) {
// https://en.wikipedia.org/wiki/List_of_HTTP_status_codes
switch(response.statusCode) {
case 200:
// content type until the first ;
myContentType=response.headers['content-type'].split(';');
myContentType=myContentType[0];
// content type
switch(myContentType) {
case 'text/html':
response.on('data', function(data) {
console.log('HTML data: ', data.toString());
});
break;
case 'text/plain':
response.on('data', function(data) {
console.log('TEXT data: ', data);
});
break;
default:
// do something about the unexpected content type!
console.log('Unexpected content type: ' + response.headers['content-type']);
}
break;
default:
// do something about the unexpected status code!
console.log('Unexpected status code: ' + response.statusCode)
break;
}
});
myRequest.end(); // this will actually send the request to the server
URL
var querystr=require('querystring');
myUrlTxt='http://www.tgunkel.de:80/index.php?query=do+it¨foo=bar';
var u=url.parse(myUrlTxt);
console.log(querystr.parse(u.query)); // { query: 'do it', foo: 'bar' }
console.log(u);
/*
{ protocol: 'http:',
slashes: true,
auth: null,
host: 'www.tgunkel.de:80',
port: '80',
hostname: 'www.tgunkel.de',
hash: null,
search: '?query=do+it¨foo=bar',
query: 'query=do+it¨foo=bar',
pathname: '/index.php',
path: '/index.php?query=do+it¨foo=bar',
href: 'http://www.tgunkel.de:80/index.php?query=do+it¨foo=bar' }
*/
// build url
var x = {
protocol: 'http',
hostname: 'www.tgunkel.de',
port: '80',
pathname: 'foo/bar',
query: { search: 'bird' }
};
url.format(x); // http://www.tgunkel.de:80/foo/bar?search=bird
TCP
http://www.hacksparrow.com/tcp-socket-programming-in-node-js.html
The TCP server
// bind to TCP port
server=net.createServer(function(sock) {
// we got a client
console.log('CONNECTED: ' + sock.remoteAddress +':'+ sock.remotePort);
// send a message to the client
sock.write('Server speaking');
// we got data from a client
sock.on('data', function(data) {
console.log("Server got this message: "+data);
});
// client goes away
sock.on('close', function(data) {
console.log('CLOSED: ');
});
}).listen(7777);
server.on('end', function() {
console.log('Client disconnected');
});
//we got a problem
server.on('error', function(err) {
console.log('Server got error'+err.toString());
});
The TCP client
// connect to TCP port
client=net.connect({ port: 7777 }, function() {
console.log('Client connected to server');
client.write('Client says hello to server');
});
client.setEncoding('utf8');
// client got data from server
client.on('data', function(data) {
console.log('Client got data: '+data);
client.write('Hey, server got your message!');
client.write('GOODBYE');
client.end();
});
// error
client.on('error', function(err) {
console.log('Client error: '+err.toString());
});