Node.js Basics
Basic Modules
Installing Prerequisites
Installing NodeJs
Install the necessary version of Node Node v8+ and NPM v5+
Confirm that node is installed
node -v
npm -v
Also installing a node server globally
npm i -g node-static
Installing MongoDb
Install Mongo from the Download page
Confirm that MongoDb is installed
mongod --version
How start a Node REPL environment
Can run standard javascript with
node
Alternatively, we can use eval with
node -e "<javascript code>"
To run a node script we use
node file.js
This can be an absolute or releative path to the file
NodeJs Globals
We are providded with some additional objects and keywords on top of javascript
global
process
module.exports
orexports
Global
Any first level global
property is available without the keywords Some poperties of the global object are as follows:
process
require
module
console
__dirname
__filename
Processes
Every Node.js script is a process
We can interact with the process by:
env
Enviromnent variablesargv
Command-line argumentsexit()
Terminate the current process
Process exit codes can be specified
// process failed
process.exit(1);
// process exited successfully
process.exit(0);
// process failed with custom exit code
process.exit(code)
Import and Export Modules
module.exports
Global property to allow a script to export something for other modules to use
module.exports = function(numbersToSum) {
let sum = 0,
i = 0,
l = numbersToSum.length;
while (i < l) {
sum += numbersToSum[i++]
}
return sum
}
require
require() is a path to a file, or a name. This will import the necessary files that we need to read. JSON files can be imported directly as an object.
const sum = require('./utility.js')
require can be used to import many types of modules as such:
const filesystem = require('fs') // core module
const express = require('express') // npm module
const server = require('./boot/server.js') // server.js file with a relative path down the tree
const server = require('../boot/server.js') // server.js file with a relative path up the tree
const server = require('/var/www/app/boot/server.js') // server.js file with an absolute path
const server = require('./boot/server') // file if there's the server.js file
const routes = require('../routes') // index.js inside routes folder if there's no routes.js file
const databaseConfigs = require('./configs/database.json') // JSON file
Core Modules
Node has a lot of preinstalled modules, the main ones are as follows:
- fs: module to work with the file system, files and folders
- path: module to parse file system paths across platforms
- querystring: module to parse query string data
- net: module to work with networking for various protocols
- stream: module to work with data streams
- events: module to implement event emitters (Node observer pattern)
- child_process: module to spawn external processes
- os: module to access OS-level information including platform, number of CPUs, memory, uptime, etc.
- url: module to parse URLs
- http: module to make requests (client) and accept requests (server)
- https: module to do the same as http only for HTTPS
- util: various utilities including promosify which turns any standard Node core method into a promise-base API
- assert: module to perform assertion based testing
- crypto: module to encrypt and hash information
fs
Handles file system operations
- fs.readFile() reads files asynchronously
- fs.readFileSync() reads files synchronously
- fs.writeFile() writes files asynchronously
- fs.writeFileSync() writes files synchronously
Reading a File
const fs = require('fs')
const path = require('path')
fs.readFile(path.join(__dirname, '/data/customers.csv'), {encoding: 'utf-8'}, function (error, data) {
if (error) return console.error(error)
console.log(data)
})
Writing to a file
const fs = require('fs')
fs.writeFile('message.txt', 'Hello World!', function (error) {
if (error) return console.error(error)
console.log('Writing is done.')
})
path
Can join a path relativley as:
const path = require('path')
const server = require(path.join('app', 'server.js'))
Or absoltely as:
const path = require('path')
const server = require(path.join(__dirname, 'app', 'server.js'))
Event emitters
We can create an EventEmitter with events
and using this we can create, listen and trigger events
Single trigger
const EventEmitter = require('events')
class Job extends EventEmitter {}
job = new Job()
job.on('done', function(timeDone){
console.log('Job was pronounced done at', timeDone)
})
job.emit('done', new Date())
job.removeAllListeners() // remove all observers
Output Job was pronounced done at ____________
Mutiple triggers
const EventEmitter = require('events')
class Emitter extends EventEmitter {}
emitter = new Emitter()
emitter.on('knock', function() {
console.log('Who's there?')
})
emitter.on('knock', function() {
console.log('Go away!')
})
emitter.emit('knock')
emitter.emit('knock')
Output
Who's there?
Go away!
Who's there?
Go away!
Single Execution of Handler
const EventEmitter = require('events')
class Emitter extends EventEmitter {}
emitter = new Emitter()
emitter.once('knock', function() {
console.log('Who's there?')
})
emitter.emit('knock')
emitter.emit('knock')
Output Who's there?
Modular events
We can use the observer pattern to modularize code. This allows us to customize modular behaviour without modifying the module.
jobs.js
const EventEmitter = require('events')
class Job extends EventEmitter {
constructor(ops) {
super(ops)
this.on('start', ()=>{
this.process()
})
}
process() {
setTimeout(()=>{
// Emulate the delay of the job - async!
this.emit('done', { completedOn: new Date() })
}, 700)
}
}
module.exports = Job
main.js
var Job = require('./job.js')
var job = new Job()
job.on('done', function(details){
console.log('Weekly email job was completed at',
details.completedOn)
})
job.emit('start')
HTTP Client
Get
Request and Response
Making an HTTP Request using http from NodeJs Core. Will receive data in chunks as follows http-get-no-buff
const http = require('http')
const url = 'http://nodeprogram.com'
http.get(url, (response) => {
response.on('data', (chunk) => {
console.log(chunk.toString('utf8'))
})
response.on('end', () => {
console.log('response has ended')
})
}).on('error', (error) => {
console.error(`Got error: ${error.message}`)
})
Alternatively, the data can be aded to a buffer until the response is complete as below http-get.js
const http = require('http')
const url = 'http://nodeprogram.com'
http.get(url, (response) => {
let rawData = ''
response.on('data', (chunk) => {
rawData += chunk
})
response.on('end', () => {
console.log(rawData)
})
}).on('error', (error) => {
console.error(`Got error: ${error.message}`)
})
Processing JSON
In order to get JSON the full response is needed, after which we parse the json to a response object
http-json-get.js
const https = require('https')
const url = 'https://gist.githubusercontent.com/azat-co/a3b93807d89fd5f98ba7829f0557e266/raw/43adc16c256ec52264c2d0bc0251369faf02a3e2/gistfile1.txt'
https.get(url, (response) => {
let rawData = ''
response.on('data', (chunk) => {
rawData += chunk
})
response.on('end', () => {
try {
const parsedData = JSON.parse(rawData)
console.log(parsedData)
} catch (e) {
console.error(e.message)
}
})
}).on('error', (error) => {
console.error(`Got error: ${error.message}`)
})
Post
To do a post we require a little but more information to be configured as such:
http-post.js
const http = require('http')
const postData = JSON.stringify({ foo: 'bar' })
const options = {
hostname: 'mockbin.com',
port: 80,
path: '/request?foo=bar&foo=baz',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(postData)
}
}
const req = http.request(options, (res) => {
res.on('data', (chunk) => {
console.log(`BODY: ${chunk}`)
})
res.on('end', () => {
console.log('No more data in response.')
})
})
req.on('error', (e) => {
console.error(`problem with request: ${e.message}`)
})
req.write(postData)
req.end()
HTTP Server
We can use node http-server.js
to run the server, we can also use node-dev
to run the server and refresh on filechange.
http-server.js
const http = require('http')
const port = 3000
http.createServer((req, res) => {
res.writeHead(200, {'Content-Type': 'text/plain'})
res.end('Hello World\n')
}).listen(port)
console.log(`Server running at http://localhost:${port}/`)
http.createServer
creates a server with a callback function which contains a response handler code
res.writeHead(200, {'Content-Type': 'text/plain'})
sets the right status code and headers
res.end()
event handler for when response is complete
listen()
specifies the port on which the server is listening
Processing a request
We can process an incoming request by reading the request properties with the following:
httP-server-request-processing.js
const http = require('http')
const port = 3000
http.createServer((request, response) => {
console.log(request.headers)
console.log(request.method)
console.log(request.statusCode)
console.log(request.url)
if (request.method == 'POST') {
let buff = ''
request.on('data', function (chunk) {
buff += chunk
})
request.on('end', function () {
console.log(`Body: ${buff}`)
response.end('\nAccepted body\n')
})
} else {
response.writeHead(200, {'Content-Type': 'text/plain'})
response.end('Hello World\n')
}
}).listen(port)