Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Node.js Development with ES2015 ->

Node.js Development with ES2015 ->

Overview slides of Node.js development. Covers also some syntax of EcmaScript 2015/2016/2017/2018/2019/2020 like await/async with promises. Example code how to build RESTful API connecting to MySQL, Sequelize ORM and MongoDB

Jussi Pohjolainen

February 24, 2021
Tweet

More Decks by Jussi Pohjolainen

Other Decks in Technology

Transcript

  1. Agenda • Node.js runtime and ES2015/2016/2017 • Architecture, Event Driven

    I/O, Working with npm, Integrating tools with Visual Studio Code, Linting, Node.js modules, Async and Promises • Node.js and building Web Server • Simple web server, express and body-parser modules, RESTful API • Database Connection • Database modules, MySQL/Sequelize ORM/MongoDB 2
  2. Node.js runtime • Node.js is an open-source, cross-platform JS run-time

    environment • https://nodejs.org/en/ • Executes JS without the browser using V8 • Let's you develop server-side scripting with JavaScript • "JavaScript everywhere" 4
  3. Node.js Internals • Applications/Modules: Your app, Node.js modules, any module

    installed by npm • V8: JavaScript engine by Google and implemented in C++. Same engine can be found from Chrome browser. • Compiles JS to machine code • libuv: C library that provides asynchronous features • Other c/c++ components: c-ares, crypto, http-parser, zlib.. (networking, compressing, encrypting) • Bindings: Glue that binds JavaScript code with C++ - code. Bindings exposes libraries written in C/C++ to JavaScript 5
  4. libuv • libuv is a multi-platform support library with a

    focus on asynchronous I/O • https://github.com/libuv/libuv • Features • Asynchronous TCP and UDP sockets • Asynchronous DNS resolution • Asynchronous file and file system operations • File system events • Node.js provides bindings for the libuv so you can use these with JavaScript 6
  5. Node.js approach: Single-threaded* • All JavaScript you write run in

    one thread, called the main thread • One thread has a event loop that accepts incoming requests • Each new request causes a JavaScript function to fire which can do stuff in non-blocking way • *But Node.js has also a lot of C++ - code.. and C++ has access to threads • JS -> Synchronous C++ // All run in the main thread • JS -> Asynchronous C++ // Can spawn a new thread! 7
  6. Node.js and Threads • So the modules you use in

    Node.js tend to be asynchronous • They do not block the main thread • function(parameters, callback) • When async module has done it's job, it calls the callback function • Control is returned to event loop • The loop decides which function was scheduled for execution 8
  7. Synchronous Example const crypto = require('crypto'); const iteration = 4

    for(let i=0; i<iteration; i++) { // Hashes passwords, takes time const key = crypto.pbkdf2Sync('secret', 'salt', 100000, 64, 'sha512'); } Time 9
  8. Asynchronous Example const crypto = require('crypto'); const iteration = 4

    for(let i=0; i<iteration; i++) { crypto.pbkdf2('secret', 'salt', 100000, 64, 'sha512', (err, key) => { console.log(key.toString('hex')); // '3745e48...08d59ae' }); } Invoke callback when job done Time 10
  9. Measuring Time const crypto = require('crypto'); const iteration = 4

    console.time("sync"); for(let i=0; i<iteration; i++) { const key = crypto.pbkdf2Sync('secret', 'salt', 100000, 64, 'sha512'); } console.timeEnd("sync"); MacBook Pro 2018: 376ms 11
  10. Measuring Time const crypto = require('crypto'); const iteration = 4

    console.time("async") for(let i=0; i<iteration; i++) { crypto.pbkdf2('secret', 'salt', 100000, 64, 'sha512', (err, key) => {}); } console.timeEnd("async") Hmm….? 12
  11. Measuring Time (without promises) const crypto = require('crypto'); const iteration

    = 4 let howManyCallbacks = 0; console.time("async") for(let i=0; i<iteration; i++) { crypto.pbkdf2('secret', 'salt', 100000, 64, 'sha512', (err, key) => { howManyCallbacks++ if(howManyCallbacks === iteration) { console.timeEnd("async") } }); } 108 ms 13
  12. Visual Studio Code - tips • Install Code Runner -

    extension for easier running of node (and other) apps • Debugging Node apps is supported by default! • Install ESLint for linting • Install Rest Client for testing 16
  13. npm package manager • Node.js contains a npm that can

    be used to install various extensions and packages • You can install packages • local (specific to your app) • ./node_modules • global (can be used everywhere) • /usr/local/lib/node_modules • When creating a node project, usually you will have a file package.json describing the project and it's dependencies 17
  14. Semantic Versioning (semver) • Version numbering: • breaking/major.feature/minor.fix/patch) • for

    example 1.5.4 • Breaking/major • End user code must be updated • Feature/minor • Adding new features • Fix/patch • Backward compatible bug fix 23
  15. Common set of rules: ^ • Common rules • I

    won’t accept any breaking changes. • I will accept new features if they’re not breaking. • I will accept any fixes if they’re not breaking. • To express this • Package version can be ^1.3.5 24
  16. Common set of rules: ~ • Common rules • I

    won’t accept any breaking changes. • I don’t need new features • I will accept any fixes if they’re not breaking. • To express this • Package version can be ~1.3.5 • And to give exact version, just use 1.3.5 25
  17. package-lock.json • The package.json contains direct dependencies • How to

    control the nested dependencies? • The package-lock.json is created for you and contains all the dependencies (dependency tree) • If package.json accept version changes in different time using npm install can result in different dependency versions (might be a problem) • The lock file locks all the versions. • When using npm install it will install exactly the same versions than in the lock file. • To update, use npm update 28
  18. 29

  19. ESLint • ESLint is linting utility (code quality) tool for

    JavaScript • To install • npm install --save-dev eslint • ESLint requires a configuration file • To create one, use • ./node_modules/eslint/bin/eslint.js --init • You can answer to questions about style guide or take popular style guides 30
  20. module.exports = { "env": { "es6": true, "node": true },

    "extends": "eslint:recommended", "parserOptions": { "sourceType": "module" }, "rules": { "no-console": "off", "indent": [ "error", 4 ], "linebreak-style": [ "error", "unix" ], "quotes": [ "error", "double" ], "semi": [ "error", "always" ] } }; Add no- console: off to init file Lot of rules https://eslint.org/docs/rules/ 33
  21. Different Style Guides • AirBnb • Google • "Standard" Style

    • Crockford's Coding Standards for JavaScript • NodeJS Style Guide 35
  22. Standard Rules • 2 spaces for indentation • Single quotes

    for string • No unused variables • No semicolons • ... • https://standardjs.com/ 39
  23. Async callback hell? • When we tend to have async

    call that has another async call (that has a async call..) it can be tedious to implement • Promises (ES2015) can help this a bit • When Node.js was implement Promises were not part of the ECMAScript so there are different approaches to this • In Util.promisify you can promisify a any callback function with result and error • So wrapping the "old" APIs with the Util.promisify can help a bit 41
  24. Using Promises function promiseFunction(resolve, reject) { // time consuming async

    stuff if(true) { resolve("OK!"); } else { reject("Failed!"); } } function onSuccess(msg) { console.log(msg); } function onError(msg) { console.log(msg); } let promise = new Promise(promiseFunction); promise.then(onSuccess).catch(onError); 42
  25. const crypto = require('crypto'); function promiseFunction(resolve, reject) { crypto.pbkdf2('secret', 'salt',

    100000, 64, 'sha512', (err, key) => { if(err) { reject(err) } else { resolve(key.toString('hex')) } }); } function onSuccess(key) { console.log(key); } function onError(msg) { console.log(msg); } let promise = new Promise(promiseFunction); promise.then(onSuccess).catch(onError); 43 Wrapping async function inside of promise
  26. Example const crypto = require('crypto'); function pdkdf2(password) { function promiseFunction(resolve,

    reject) { crypto.pbkdf2(password, 'salt', 100000, 64, 'sha512', (err, key) => { if(err) { reject(err) } else { resolve(key.toString('hex')) } }); } return new Promise(promiseFunction) } pdkdf2('mypassword').then((key) => console.log(key)).catch((err) => console.log(err)); 44 Function returning a promise will create a cleaner solution
  27. Node.JS callbacks const fs = require('fs'); fs.readFile('mytest.json', function (error, text)

    { if (error) { console.error('Error while reading config file'); } else { try { const obj = JSON.parse(text); console.log(JSON.stringify(obj)); } catch (e) { console.error('Invalid JSON in file'); } } } ); 45 Async function for reading a file Notice two different approaches for error handling
  28. Node.JS promise const util = require('util'); const fs = require('fs');

    const promiseReadFile = util.promisify(fs.readFile); promiseReadFile('mytest.json') .then(function (text) { // const obj = JSON.parse(text); console.log(JSON.stringify(obj)); }) .catch(function (error) { // // File read error or JSON SyntaxError console.error('An error occurred', error); }); 46 util.promisify is Node 8 feature Now we can do the same with promises. Notice that one catch for every exception or error
  29. ES2017: async / await • When chaining multiple promises the

    code can get also complicated • doSomething().then((result) => something(result)).then(…).then(…)… • async and await can help 47
  30. What Happens Here? const fetch = require('node-fetch') fetch('https://swapi.co/api/people/1/') .then((httpResp1) =>

    httpResp1.json()) .then((characterJson) => fetch(characterJson.films[0])) .then((httpResp2) => httpResp2.json()) .then((filmJson) => console.log(filmJson)) 48
  31. Async function function f1() { // Returns a resolved Promise

    object with the given value return Promise.resolve(1); } f1().then((integer) => console.log(integer)); // 1 async function f2() { return 1 } f2().then((integer) => console.log(integer)) 49
  32. Async function function f1() { // Returns a resolved Promise

    object with the given value return Promise.resolve(1); } f1().then((integer) => console.log(integer)); // 1 async function f2() { return 1 } f2().then((integer) => console.log(integer)) 50 Will return a promise!
  33. Promise (recap) function delay(secs, text) { function promiseFunction(resolve, reject) {

    setTimeout(() => resolve(text), secs) } return new Promise(promiseFunction) } delay(1000, 'hello').then((text) => console.log(text)) Will output ’hello’ after 1000 sec 51
  34. With async there is await function delay(secs, text) { function

    promiseFunction(resolve, reject) { setTimeout(() => resolve(text), secs) } return new Promise(promiseFunction) } async function doIt() { let text = await delay(1000, 'hello') console.log(text) } console.log('call async function') doIt() console.log('async function has been called') Waits until the result. Execution still continues in other parts of the app (async) 52 Output: call async function async function has been called hello
  35. Using async function delay(secs, text) { function promiseFunction(resolve, reject) {

    setTimeout(() => resolve(text), secs) } return new Promise(promiseFunction) } async function doIt() { let text1 = await delay(1000, 'hello') let text2 = await delay(1000, text1 + ' world') return text2 // Promise.resolve(text2) } doIt().then((result) => console.log(result)) Returns a promise! 53 Order here is guaranteed! Two delay promises are run in particular order. Both are run in async
  36. Without async function delay(secs, text) { function promiseFunction(resolve, reject) {

    setTimeout(() => resolve(text), secs) } return new Promise(promiseFunction) } delay(1000, 'hello’) .then((text1) => delay(1000, text1 + ' world’)) .then(text2 => console.log(text2)) Can be a bit hard to read.. 54
  37. Without async const fetch = require('node-fetch') fetch('https://swapi.co/api/people/1/') .then((httpResp1) => httpResp1.json())

    .then((characterJson) => fetch(characterJson.films[0])) .then((httpResp2) => httpResp2.json()) .then((filmJson) => console.log(filmJson)) 55 Can be a bit hard to read..
  38. With async and await const fetch = require('node-fetch') async function

    fetchFilm(url) { const httpResp1 = await fetch(url) const characterJson = await httpResp1.json() const httpResp2 = await fetch(characterJson.films[0]) const filmJson = await httpResp2.json() return filmJson } fetchFilm('https://swapi.co/api/people/1/’) .then((filmJson) => console.log(filmJson)).catch(err => console.log(err)) 56 Easier to understand?
  39. Year Edition Naming 1997 1 .. 1998 2 .. 1999

    3 Regex, better string handling, try/catch,... Abandoned 4 .. 2009 5 strict mode, getters and setters, JSON.. 2015 6 ES2015 classes, modules, arrow functions, collections ... 2016 7 ES2016 Math.pow => **, array.prototype.includes 2017 8 ES2017 await/async 2018 9 ES2018 spread operator, rest parameters, async iteration 2019 10 ES2019 Array.flat, Array.flatMap 2020 11 ES2020 BigInt, nullish coalescing operator, optional chaining, globalThis ESNext await and async is rather new 58
  40. Some new ES2015 New Features • Arrow Functions • Parameter

    values • Object properties • Classes • Modules 59
  41. Lexical this var object = { array: [0,1,2,3,4], doIt: function()

    { this.array.forEach(function(value) { this.array.push(value); }); } } object.doIt(); Cannot read property 'push' of undefined 60
  42. Lexical this var object = { array: [0,1,2,3,4], doIt: function()

    { var _this = this; this.array.forEach(function(value) { _this.array.push(value); }); } } object.doIt(); It works when using closure 61
  43. Lexical this var object = { array: [0,1,2,3,4], doIt: function()

    { this.array.forEach((value) => { this.array.push(value); }); } } object.doIt(); Works! 62
  44. Variadic Parameter Values function printIt(amount, ...text) { for(let i =

    0; i < amount; i++) { for(let j = 0; j < text.length; j++) { console.log(text[i]); } } } printIt(1, "text"); printIt(2, "hello", "world"); 63
  45. Interpolation of String var message = "hello"; var html =

    ` <div> <p>${message}</p> </div> `; console.log(html); 64
  46. Object Properties let x = 0; let y = 1;

    let obj = { x, y }; console.log(obj.x); console.log(obj.y); 65
  47. class Shape { constructor(x, y, color) { this.x = x;

    this.y = y; this.color = color; } } class Rectangle extends Shape { constructor (x, y, color, width, height) { super(x, y, color); this.width = width; this.height = height; } } class Circle extends Shape { constructor (x, y, color, radius) { super(x, y, color); this.radius = radius; } } let circle = new Circle(0,0,"red",5); console.log(circle); A lot nicer syntax for creating inheritance! 66
  48. class Shape { constructor(x, y, color) { this.x = x;

    this.y = y; this.color = color; } } class Rectangle extends Shape { constructor (x, y, color, width, height) { super(x, y, color); this.width = width; this.height = height; } } class Circle extends Shape { constructor (x, y, color, radius) { super(x, y, color); this.radius = radius; } } Shape.prototype.hello = "world"; let circle = new Circle(0,0,"red",5); console.log(circle.hello); But it is syntactical sugar!! 67
  49. About Modules • Modules Systems 1. AMD Specification (RequireJS) 2.

    CommonJS Modules (NodeJS) 3. ES2015 official module (React) • In EcmaScript 2015 for the first time it's built into language. • In node 8.5.0 you can use these as ”experimental”. In Node 10.0 LTS the flag should be removed • node --experimental-modules index.js • It's possible to compile ES6 Modules to AMD or CommonJS 69
  50. EcmaScript 2015: app.js import { generateRandom, sum } from './utility.js';

    console.log(generateRandom()); // logs a random number console.log(sum(1, 2)); // 3 70
  51. EcmaScript 2015: utility.js function generateRandom() { return Math.random(); } function

    sum(a, b) { return a + b; } export { generateRandom, sum } 71
  52. Modify package.json { "name": "projekti", "version": "1.0.0", "description": "", "main":

    "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC", "type": "module" } 72
  53. CommonJS • CommonJS is a project with the goal of

    specifying ecosystem for JS outside of Browser • Was started by Mozilla engineer, inital name ServerJS • CommonJS described a lot of specifications, including modules • This module specification is implemented in NodeJS • require to include modules • exports to make things available 74
  54. Example Module: randomModule.js 'use strict'; /** * Returns random integer

    number between [min, max]. * @param {number} min * @param {number} max * @return {number} */ module.exports = function(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; }; Uses JSdoc 75 Exports the function
  55. Exporting Object 'use strict'; var MyMath = { random: function(min,

    max) { return Math.floor(Math.random() * (max - min + 1)) + min; }, abs: function(value) { return (value < 0) ? value * -1: value; } }; module.exports = MyMath; 77 Exporting a whole object
  56. ES9: Spread Operator function sum(x, y, z) { return x

    + y + z; } const numbers = [1, 2, 3]; console.log(sum(...numbers)); 79
  57. ES9: Spread Operator let parts = ['shoulders', 'knees']; let lyrics

    = ['head', ...parts, 'and', 'toes']; // ["head", "shoulders", "knees", "and", "toes"] 80
  58. ES9: Spread Operator let obj1 = { foo: 'bar', x:

    42 }; let obj2 = { foo: 'baz', y: 13 }; let clonedObj = { ...obj1 }; // Object { foo: "bar", x: 42 } let mergedObj = { ...obj1, ...obj2 }; // Object { foo: "baz", x: 42, y: 13 } 81
  59. ES11: Nullish coalescing operator undefined ?? "string" // -> "string"

    null ?? "string" // "string" false ?? "string" // -> false NaN ?? "string" // -> NaN 82
  60. flat const arr1 = [0, 1, 2, [3, 4]]; console.log(arr1.flat());

    // expected output: [0, 1, 2, 3, 4] const arr2 = [0, 1, 2, [[[3, 4]]]]; console.log(arr2.flat(2)); // expected output: [0, 1, 2, [3, 4]] 84
  61. Output of this? const doIt1 = function() { console.log(this) }

    const doIt2 = () => { console.log(this) } doIt1() doIt2() console.log(this) 86
  62. Remember lexical this… const doIt1 = function() { console.log(this) }

    const doIt2 = () => { console.log(this) } var _this = this const doIt2 = function () { console.log(_this) } doIt1() doIt2() console.log(this) 87 The arrow syntax uses this from “global” scope “global” scope here has different meaning for this than inside of a function..
  63. Using this in functions function doIt(name) { this.name = name

    } let obj = {} doIt.apply(obj, ["jack"]) console.log(obj) 88 this now refers to obj Calling the function and defining the meaning of this
  64. Keyword this in Node.js: Wrapper Function var context = (function

    (exports, require, module, __filename, __dirname) { // Your code }); var module = {exports:{}} context.apply(module.exports, [module.exports, require, module, "FILE_NAME", "DIR_NAME"]); 89 In Node, your whole code is inside of a wrapper function! Calling the wrapper function and defining the meaning of this
  65. Http Server: index.js const http = require('http') // Create a

    server (http.Server) and provide a callback function const server = http.createServer((request, response) => { response.end('Path: ' + request.url) }) // Start the server in port 8080 server.listen(8080, () => console.log(`Server listening in port ${server.address().port}`)) http.IncomingMessage http.ServerResponse 97
  66. Express.js • Express.js is a Node.js web application server framework

    • Gives you a layer of fundamental web application features • To install: • npm install express 98
  67. Web Server 'use strict' const express = require('express') // App

    object has methods for routing http requests, configuring // middleware, rendering html pages, registering template engine const app = express() // Listen requests for root (/) app.get('/', (req, res) => { res.send('Hello World!') }) const server = app.listen(8080, () => { console.log(`Listening on port ${server.address().port}`) }) 99
  68. Tip: nodemon • To restart server automatically after changing code,

    use nodemon instead of node • npm install -g nodemon • And • nodemon myapp.js • Workflow without nodemon • https://twitter.com/unicodeveloper/status/1037712553873424385 100
  69. Middleware • Middleware is a function that receives request and

    response - objects • Can • Execute code • Make changes to request and response objects • End the req/res cycle • Call the nest middleware function • Different types of middleware • App level • Router level • Error handling • ... 102
  70. Application level app.use((req, res, next) => { console.log(new Date(), req.method,

    req.url) next() }) app.use('/someurl', (req, res, next) => { console.log(new Date(), req.method, req.url) next() }) Called when url contains /someurl 103
  71. Router middleware • Router is kind of "mini-application" • Router

    behaves like middleware, so you can use it with app.use() • To create router, use • let router = express.Router() • Then you can add http method routes to the object • router.get('/router1', (req, res) => { res.send('router 1') }) • And add it as a middleware • app.use('/root', router) 104
  72. 'use strict' const express = require('express') const app = express()

    const listener = app.listen(8080, () => { console.log(`Listening on port ${listener.address().port}`) }) // Creating router - object let calendar = express.Router() let users = express.Router() // Use it as middleware app.use('/calendar', calendar) app.use('/users', users) calendar.get('/2018-09-09', (req, res) => { res.send('calendar information') }) users.get('/1', (req, res) => { res.send('user information') }) 105 Called when url contains /calendar/2018-09-09
  73. Separating routing to different file app.js 'use strict' const express

    = require('express') const app = express() const users = require('./routes/index.js') // Use it as middleware app.use('/users', users) const listener = app.listen(8080, () => { console.log(`Listening on port ${listener.address().port}`) }) routes/index.js 'use strict' const express = require('express') let users = express.Router() users.get('/1', (req, res) => { res.send('user information') }) module.exports = users 107
  74. Routing 'use strict' const express = require('express') let users =

    express.Router() users.get('/1', (req, res) => { res.send('Getting user') }) users.post('/', (req, res) => { res.send('Adding user') }) users.delete('/1', (req, res) => { res.send('Deleting user') }) module.exports = users 109
  75. Routing, using Regex 'use strict' const express = require('express') let

    users = express.Router() const number = new RegExp('^/[0-9]+$') users.get(number, (req, res) => { res.send('Getting user') }) users.get(/^\/test$/, (req, res) => { res.send('Test user') }) module.exports = users /99 /test 110
  76. Path to Regexp • Path-to-regexp is a module that turns

    string into regular expression • https://www.npmjs.com/package/path-to-regexp • It will make easier to create regexp objects, especially if they have parameters • For example, a string containing '/[1-9]+' is transformed into a regex object /^\/[1-9]+$/ 111
  77. Routing, using path to regexp 'use strict' const express =

    require('express') let users = express.Router() users.get('/[1-9]+', (req, res) => { res.send('Getting user') }) users.get('/test', (req, res) => { res.send('Test user') }) module.exports = users 112 string => regexp
  78. Using parameters 'use strict' const express = require('express') let users

    = express.Router() users.get('/:myVariable([1-9]+)', (req, res) => { res.send(`Getting user ${req.params.myVariable}`) }) module.exports = users 113 Create a new variable containing the stuff in url Use req – object to access the variable
  79. Creating "Data object" class User { constructor (id, name) {

    this.id = id this.name = name } } module.exports = User Just a plain class for creating users 115
  80. 'use strict' const User = require('../dataobjects/user.js') const express = require('express')

    let users = express.Router() const database = new Set([new User(1, 'jack smith'), new User(2, 'tina jackson')]) users.get('/:urlId([1-9]+)', (req, res) => { let userObject = {} const urlId = Number(req.params.urlId) database.forEach((user) => { if (user.id === urlId) { userObject = user } }) res.send(JSON.stringify(userObject)) }) module.exports = users Creating "database" Importing the class If user with given id is found Sends a string response 116
  81. Headers curl -i http://localhost:8080/users/1 HTTP/1.1 200 OK X-Powered-By: Express Content-Type:

    text/html; charset=utf-8 Content-Length: 28 ETag: W/"1c-VJ4vRdnoG3woR9lnRtdA+3Qm+l4" Date: Thu, 16 Aug 2018 09:35:57 GMT Connection: keep-alive {"id":1,"name":"jack smith"} Well this is not right... 117
  82. Response methods Sets also the content- type: res.json("{}") But this

    can detect automatically if given json res.send({}) 118
  83. 'use strict' const User = require('../dataobjects/user.js') const express = require('express')

    let users = express.Router() const database = new Set([new User(1, 'jack smith'), new User(2, 'tina jackson')]) users.get('/:urlId([1-9]+)', (req, res) => { let userObject = {} const urlId = Number(req.params.urlId) database.forEach((user) => { if (user.id === urlId) { userObject = user } }) res.send(userObject) }) module.exports = users No need for transform the json to string 119
  84. HTTP POST BODY Parsers • In most recent version of

    Express, http post body parser is prebuilt and to be used as middleware app.use(express.json()) • This will take the HTTP POST Body and transform it to json and can be read from request object users.post('/', (req, res) => { let user = req.body database.add(user) res.send(user) }) 120
  85. Using Databases • Adding capability to connect to database is

    just a matter of installing Node.js db driver • For each database you will have different driver • MySQL • MongoDB • PostgreSQL ... • Installing the driver, for example mysql • npm install mysql 122
  86. MariaDB [test]> create table users (id int NOT NULL AUTO_INCREMENT,

    name varchar(255) NOT NULL, PRIMARY KEY (id)); Query OK, 0 rows affected (0.01 sec) MariaDB [test]> insert into users (name) values ('jack smith'); Query OK, 1 row affected (0.01 sec) MariaDB [test]> insert into users (name) values ('tina jackson'); Query OK, 1 row affected (0.00 sec) MariaDB [test]> select * from users; +----+--------------+ | id | name | +----+--------------+ | 1 | jack smith | | 2 | tina jackson | +----+--------------+ 2 rows in set (0.01 sec) 123
  87. npm install mysql const mysql = require('mysql') const connection =

    mysql.createConnection({ host: 'localhost', user: '', password: '', database: 'test' }) connection.connect() connection.query('select * from users', (err, users) => { if (err) { throw err } users.forEach((user) => console.log(`${user.id} ${user.name}`)) }) // will wait if previously enqueued queries connection.end() 124
  88. Insert const mysql = require('mysql') const connection = mysql.createConnection({ host:

    'localhost', user: '', password: '', database: 'test' }) connection.connect() connection.query('insert into users (name) values ("tina jackson")', (err, result) => { if (err) { throw err } console.log(result.affectedRows) }) // will wait if previously enqueued queries connection.end() 125
  89. const User = require('../dataobjects/user.js') const express = require('express’) let users

    = express.Router() const crudRepository = require('../database/crudrepository.js') users.get('/', (req, res) => { crudRepository.findAll((result) => res.send(result)) }) users.post('/', (req, res) => { let user = req.body crudRepository.save(user, (result) => res.send(result)) }) module.exports = users 127 The router here is unaware of the database. CrudRepository contains basic function for finding and saving
  90. config.js const config = { host: 'localhost', user: '', password:

    '', database: 'test' } module.exports = config 128
  91. const mysql = require('mysql') const config = require('./config.js') class CrudRepository

    { constructor () { this.connection = mysql.createConnection(config) this.connection.connect() // If ctrl-c, end connection process.on('SIGINT', () => this.connection.end(() => process.exit())); } save (user, callback) { const sql = `insert into users (name) values ('${user.name}')` this.connection.query(sql, (err, results) => { callback({"id": results.insertId}) }) } findAll (callback) { this.connection.query('select * from users', (err, users) => { callback(users) }) } } module.exports = new CrudRepository() 129
  92. Sequelize • Sequelize is a promise-based Node.js ORM for •

    Postgres • MySQL, MariaDB • SQLite • Microsoft SQL Server 131
  93. Getting Started • Install sequelize • npm install sequelize •

    And your database • npm install mysql2 | mariadb | sqlite3 | tedious 132
  94. Connection: MariaDB const sequelize = new Sequelize("localhost", "user", "pw", {

    host: "localhost", dialect: "mariadb", define: { timestamps: false, }, }); 133 By default, Sequelize automatically adds the fields createdAt and updatedAt to your table. You can disable this feature.
  95. Connection: SQLite const sequelize = new Sequelize({ dialect: "sqlite", storage:

    "path/to/db.sqlite" define: { timestamps: false, }, }); 134
  96. Testing the Connection // Location will be the table name

    to be Locations, // even person -> people will work! const Location = sequelize.define("Location", { latitude: { type: DataTypes.FLOAT }, longitude: { type: DataTypes.FLOAT }, }); const connect = async () => { await sequelize.authenticate(); // creates the table if it doesn't exist await Location.sync(); console.log("database connection now open"); }; connect(); 136
  97. Usage let all = await Location.findAll() let one = await

    Location.findAll({ where: { id : 1 }}) let result = await Location.destroy({ where: { id }}) let result = await Location.create({ .. }) 137
  98. MongoDB • MongoDB is document-oriented database, like noSQL • Uses

    JSON – like documents • Collections are like ”tables” and contains documents • Documents are JSON data • There are no fixed schema 138
  99. Default db location By default /data/db is the location for

    the db files. Must have proper r/w access 140
  100. To start mongo • You can define mongodb path •

    mongod --dbpath /new/path/ • And after this • mongo 141
  101. Usage from cli • Show databases • show databases •

    Create database • use locationsdb • Insert into locationsdb a new collection with a document • db.locationscollection.insert({longitude: 60, latitude: 60}) • Select * • db.locationscollection.find() • Select the document with longitude = 60 • db.locationscollection.find({longitude: 60}) • To see which db is active • db 143
  102. 144

  103. 145

  104. 146

  105. 147

  106. 148

  107. Node.js mongodb driver • Install • npm install mongodb •

    In code require MongoClient • const MongoClient = require('mongodb').MongoClient; • And connect • const url = 'mongodb://localhost:27017'; • MongoClient.connect(url, {useNewUrlParser: true}, (err, client) => { .. } 149
  108. Example const MongoClient = require('mongodb').MongoClient; const url = 'mongodb://localhost:27017’; MongoClient.connect(url,

    {useNewUrlParser: true}, (err, client) => { if(err) { throw err } console.log("Connected successfully to server") const database = client.db('locationsdb’) client.close() }); 150
  109. const MongoClient = require('mongodb').MongoClient; const url = 'mongodb://localhost:27017'; MongoClient.connect(url, {useNewUrlParser:

    true}, (err, client) => { if(err) { throw err } console.log("Connected successfully to server") const database = client.db('locationsdb') const loc = {latitude: 50, longitude: 60} insertDocument(loc, database, (result) => { console.log(result.insertedCount) client.close() }) }); const insertDocument = function(obj, db, callback) { const collection = db.collection('locationscollection'); collection.insertOne(obj, (err, result) => { if(err) { throw err } console.log("Inserted document into the collection"); callback(result); }); } Function that inserts a doc 151
  110. Finding const findAll = function(db, callback) { const collection =

    db.collection('locationscollection'); collection.find({}).toArray(function(err, docs) { if(err) { throw err } callback(docs); }); } 152
  111. const MongoClient = require('mongodb').MongoClient; const url = 'mongodb://localhost:27017'; MongoClient.connect(url, {useNewUrlParser:

    true}, (err, client) => { if(err) { throw err } console.log("Connected successfully to server") const database = client.db('locationsdb') const loc = {latitude: 50, longitude: 60} insertDocument(loc, database, (result) => { console.log(result.insertedCount) findAll(database, (result) => { console.log(result) client.close() }) }) }); 153