part 1

Agenda
-
Whats this?
-
Tools from node
-
MongoDB
-
Our first route
-
Callbacks -> promises -> async/await
-
Templates
What are we building?
a company directory with skills
Repository
git clone git@github.com:goofyahead/NodeJS-crash-course.git
NodeJS

NodeJS
-
Event-driven
-
Single-thread
-
javascript
-
V8 engine -> ES6
-
Events - async APIS - non blocking IO
Non blocking IO

The event loop

V8


To the code!

Setup
mkdir myAwesomeApp
cd myAwesomeApp
#(OPEN OUR EDITOR WITH THE FOLDER)
npm init
https://github.com/creationix/nvm//index.js
console.log('hello')"scripts": {
"start": "node index.js",
"test": "echo \"Error: no test specified\" && exit 1"
},Run
npm start
Our first endpoint

http module
https://nodejs.org/api/http.html#http_httpconst http = require('http')
const port = 8080
const server = http.createServer((req, res) => {
res.end('hello from server')
})
server.listen(port, () => {
console.log(`server running on ${port}`)
})step-1
the libraries
npm install --save hapiconst Hapi = require('hapi');
const server = Hapi.server({
port: 3000,
host: 'localhost'
});
const init = async () => {
await server.start();
console.log(`Server running at: ${server.info.uri}`);
};
process.on('unhandledRejection', (err) => {
console.log(err);
process.exit(1);
});
init();step-1
hapi routes
server.route({
method: 'GET',
path: '/',
handler: (request) => {
return 'Hello, world!';
}
});
server.route({
method: 'GET',
path: '/person/{name}',
handler: (request) => {
return `Hello, ${encodeURIComponent(request.params.name)}!`;
}
});step-1
You are a backend dev now!

The database

MongoDB
mongod --config /usr/local/etc/mongod.conf> mongo myDb
db.stats()
{
"db" : "test",
"collections" : 0,
...
"ok" : 1
}
db.people.insert({name: 'alex', skills: ['android','java','tortilla'],picture: ''})
db.people.find()
{ "_id" : ObjectId("5b16655b8e0185012b273dd8"),
"name" : "alex",
"skills" : [ "android", "java", "tortilla" ],
"picture" : "" }step-2
Access it from our code
npm install mongodb --saveconst MongoClient = require('mongodb').MongoClient;
// Connection URL
const url = 'mongodb://localhost:27017';
// Database Name
const dbName = 'myDb';
class Db {
constructor (){
MongoClient.connect(url, function(err, client) {
console.log("Connected successfully to server");
const db = client.db(dbName);
});
}
getPeople(){
return 'people!'
}
}
module.exports = new Db()step-2
Access it from our code
getPeople(callback){
const collection = this.db.collection(collectionName)
// Find some documents
collection.find(whereClause).toArray(function(err, docs) {
console.log("Found the following records")
console.log(docs)
callback(docs)
})
}step-2
server.route({
method: 'GET',
path: '/people',
handler: (request) => {
Db.getPeople((people) => {
console.log(people)
return (people)
})
}
})What's this?
core.js:125 Debug: internal, implementation, error
Error: handler method did not return a value, a promise, or throw an error
at module.exports.internals.Manager.execute (/Users/tsl057/github/myAwesomeApp/node_modules/hapi/lib/toolkit.js:52:29)
at process._tickCallback (internal/process/next_tick.js:68:7)
step-2
With promises
server.route({
method: 'GET',
path: '/people',
handler: (request) => {
return new Promise(function (resolve, reject) {
Db.getPeople((people) => {
console.log(people)
resolve(people)
})
})
}
})step-3
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
Callbacks
Promises
async/await

step-4
Callback
getPeople(callback){
const collection = this.db.collection(collectionName)
// Find some documents
collection.find(whereClause).toArray(function(err, docs) {
console.log("Found the following records")
console.log(docs)
callback(docs)
})
}step-4
Callback hell
fs.readdir(source, function (err, files) {
if (err) {
console.log('Error finding files: ' + err)
} else {
files.forEach(function (filename, fileIndex) {
console.log(filename)
gm(source + filename).size(function (err, values) {
if (err) {
console.log('Error identifying file size: ' + err)
} else {
console.log(filename + ' : ' + values)
aspect = (values.width / values.height)
widths.forEach(function (width, widthIndex) {
height = Math.round(width / aspect)
console.log('resizing ' + filename + 'to ' + height + 'x' + height)
this.resize(width, height).write(dest + 'w' + width + '_' + filename, function(err) {
if (err) console.log('Error writing file: ' + err)
})
}.bind(this))
}
})
})
}
})step-4
Promises
const x = new Promise( function (resolve, reject) {
// do something asynchronous
reject(err)
resolve(result)
})doSomething()
.then(result => doSomethingElse(result))
.then(newResult => doThirdThing(newResult))
.then(finalResult => {
console.log(`Got the final result: ${finalResult}`);
})
.catch(failureCallback);http://bluebirdjs.com/docs/api/promise.promisifyall.htmlstep-4
async / await
const makeRequest = () =>
getJSON()
.then(data => {
console.log(data)
return "done"
})
makeRequest()https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_functionconst makeRequest = async () => {
console.log(await getJSON())
return "done"
}
makeRequest()step-4
async / await
const makeRequest = () => {
return getJSON()
.then(data => {
if (data.needsAnotherRequest) {
return makeAnotherRequest(data)
.then(moreData => {
console.log(moreData)
return moreData
})
} else {
console.log(data)
return data
}
})
}step-4
async / await
const makeRequest = async () => {
const data = await getJSON()
if (data.needsAnotherRequest) {
const moreData = await makeAnotherRequest(data);
console.log(moreData)
return moreData
} else {
console.log(data)
return data
}
}
step-4

more than json
step-5
server side rendering
step-5
https://github.com/hapijs/vision
adding plugins
step-5
const init = async () => {
await server.register(Vision);
server.views({
engines: { html: Handlebars },
relativeTo: __dirname,
path: `templates`
});
await server.start();
console.log('Server is running at ' + server.info.uri);
};const Hapi = require('hapi')
const Vision = require('vision')
const Handlebars = require('handlebars')rendering
step-5
server.route({
method: 'GET',
path: '/render/people/{name}',
handler: async (request, h) => {
const person = await Db.getPerson(request.params.name)
return h.view('person', {
message: 'Hello Handlebars!',
person: person
});
}
})templates
step-5
<html>
<head title='{{message}}'>
<body>
<div>
<h1>{{person.name}}</h1>
<ul>
{{#each person.skills}}
<li>{{this}}</li>
{{/each}}
</ul>
<img src='{{person.picture}}'/>
</div>
</body>
</html>
Questions?

Homework
- Play around with this (promises and =>)
- Understand module.exports
- Allow insertion of people REST
- Form to perform insert with
body - Go to MDN and node website!

NodeJS part 1
By Alejandro Vidal Rodriguez
NodeJS part 1
- 42