npm init -y
npm i express

package.json

{
	"scripts": {
		"start": "node index.js",
		"dev": "nodemon index.js"
	}
}

index.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
const express = require('express');
const port = 5000;
const app = express();

let users = [
	{ id: 1, name: 'nisim', age: 42 },
	{ id: 2, name: 'shlomo', age: 23 },
	{ id: 3, name: 'david', age: 666 },
];

app.use(express.json());

app.get('/ping', (req, res) => res.send('pong'));

app.get('/users', (req, res) => {
	res.json(users);
});

app.get('/users/:id', (req, res) => {
	const givenUserId = parseInt(req.params.id);
	const requestedUser = users.find(u => u.id === givenUserId);
	res.json(requestedUser);
});

app.post('/users', (req, res) => {
	const userToAdd = req.body;
	userToAdd.id = 666;
	users.push(userToAdd);
	res.status(201).send(`${userToAdd.name} was added`);
});

app.delete('/users/:id', (req, res) => {
	const givenUserId = parseInt(req.params.id);
	users = users.filter(u => u.id !== givenUserId);
	res.send(`user with id ${givenUserId} was deleted`);
});

app.listen(port, () => {
	console.log('listen to port', port);
});

Express Router

routes/usersRouter.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
const express = require('express');
const router = express.Router();

let users = [
	{ id: 1, name: 'nisim', age: 42 },
	{ id: 2, name: 'shlomo', age: 23 },
	{ id: 3, name: 'david', age: 666 },
];

router.get('/', (req, res) => {
	res.json(users);
});

router.get('/:id', (req, res) => {
	const givenUserId = parseInt(req.params.id);
	const requestedUser = users.find(u => u.id === givenUserId);
	res.json(requestedUser);
});

router.post('/', (req, res) => {
	const userToAdd = req.body;
	userToAdd.id = 666;
	users.push(userToAdd);
	res.status(201).send(`user ${userToAdd.name} was added`);
});

router.delete('/:id', (req, res) => {
	const givenUserId = parseInt(req.params.id);
	users = users.filter(u => u.id !== givenUserId);
	res.send(`user with id ${givenUserId} was deleted`);
});

module.exports = router;

and refactor the index.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
const express = require('express');
const port = 5000;

const app = express();

app.use(express.json());

app.get('/ping', (req, res) => {
    res.send('pong');
});

app.use('/users', require('./routes/usersRoutes'));

app.listen(port, () => {
    console.log('listen to port', port);
});

Manual Server Testing

print all users

curl "localhost:5000/users"

print user by id

curl "localhost:5000/users/1"
curl "localhost:5000/users/2"
curl "localhost:5000/users/3"

insert “Avi Biter”

curl -X POST -H "Content-Type: application/json" \
	-d '{"name": "avi biter", "age": 25}' \
	"localhost:5000/users"

delete “Avi Biter”

curl -X DELETE "localhost:5000/users/666"

Test MongoDB

npm i mongoose dotenv

.env

ATLAS_HOST=www.atlasmashu.com
ATLAS_USER=my-user
ATLAS_PASS=my-secret

test.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
require('dotenv').config();
const mongoose = require('mongoose');

const userSchema = new mongoose.Schema({
	name: String,
	age: Number,
});

const User = mongoose.model('user', userSchema);

main();

async function main() {
	mongoose.connect(`mongodb+srv://${process.env.ATLAS_HOST}`, {
		user: process.env.ATLAS_USER,
		pass: process.env.ATLAS_PASS,
		dbName: 'my-db-name'
	});
	console.log(await User.find({}));
	mongoose.connection.close();
}

Break Script Into Files

we will create:

  • db.js
  • models/User.js

db.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
require('dotenv').config();
const mongoose = require('mongoose');

function connect() {
	mongoose.connect(`mongodb+srv://${process.env.ATLAS_HOST}`, {
		user: process.env.ATLAS_USER,
		pass: process.env.ATLAS_PASS,
		dbName: 'bakery'
	});
}

function disconnect() {
	mongoose.connection.close();
}

module.exports = { connect, disconnect }

User.js

const mongoose = require('mongoose');

const userSchema = new mongoose.Schema({
	name: String,
	age: Number,
});

module.exports = mongoose.model('user', userSchema);

test.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
const User = require('./models/User');
const db = require('./db');

main();

async function main() {
	db.connect();
	console.log(await User.find({}));
	db.disconnect();
}

more tests:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
const User = require('./models/User');
const db = require('./db');

main();

async function main() {
	db.connect();
	await printAllUsers();
	await addAviBiter();
	await addTurtles();
	await deleteAllUsers();
	db.disconnect();
}

async function printAllUsers() {
	console.log(await User.find({}));
}

async function addAviBiter() {
	const user = await User.create({ name: "avi biter", age: 18 });
	console.log(user.name, 'was added');
}

async function addTurtles() {
	const turtles = [
		{ name: "rafael", age: 2 },
		{ name: "donatelo", age: 2 },
		{ name: "mikelangelo", age: 2 },
		{ name: "leonardo", age: 2 },
	];
	await User.insertMany(turtles);
	console.log('the turtles were added');
}

async function deleteAllUsers() {
	await User.deleteMany({});
	console.log('users collection is clean now');
}

Reset Script

package.json

1
2
3
4
5
6
7
{
	"scripts": {
		"start": "node index.js",
		"dev": "nodemon index.js",
		"resetDB": "node resetDB.js"
	}
}

resetDB.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
const db = require('./db');
const User = require('./models/User');

main();

async function main() {
	db.connect();
	await resetDB();
	db.disconnect();
}

async function resetDB() {
	await cleanDB();
	await addDataSample();
}

async function addDataSample() {
	const sampleOfUsers = require('./dataSample.json').users;
	console.log('inserting data sample...');
	await User.insertMany(sampleOfUsers);
	console.log('data sample was inserted');
}

async function cleanDB() {
	console.log('cleanning db...');
	await User.deleteMany({});
	console.log('db is clean');
}

dataSample.json

{
	"users": [
		{ "name": "nisim", "age": 42 },
		{ "name": "shlomo", "age": 23 },
		{ "name": "david", "age": 666 }
	]
}

Refactor REST API to use mongoDB

index.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
const db = require('./db');
const port = 5000;
const express = require('express');
const app = express();

db.connect();

app.use(express.json());
app.get('/ping', (req, res) => res.send('pong'));
app.use('/users', require('./routes/usersRoutes'));

app.listen(port, () => {
    console.log('listen to port', port);
});

usersRoutes.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const express = require('express');
const router = express.Router();
const User = require('../models/User');

router.get('/', async (req, res) => {
	res.json(await User.find({}));
});

router.get('/:id', async (req, res) => {
	res.json(await User.findById(req.params.id));
});

router.post('/', async (req, res) => {
	const userToAdd = await User.create(req.body);
	res.status(201).send(`${userToAdd.name} was added`);
});

router.delete('/:id', async (req, res) => {
	const userToDelete =
		await User.findByIdAndDelete(req.params.id);
	res.send(`${userToDelete.name} was deleted`);
});

module.exports = router;

We should handle exceptions

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
const express = require('express');
const router = express.Router();
const User = require('../models/User');

router.get('/', async (req, res) => {
	try {
		res.json(await User.find({}));
	}
	catch (error) {
		res.status(500).send('server error');
	}
});

router.get('/:id', async (req, res) => {
	try {
		const requestedUser = await User.findById(req.params.id);
		res.json(requestedUser);
	}
	catch (error) {
		res.status(500).send('server error');
	}
});

router.post('/', async (req, res) => {
	try {
		const userToAdd = await User.create(req.body);
		res.status(201).send(`${userToAdd.name} was added`);
	}
	catch (error) {
		res.status(500).send('server error');
	}
});

router.delete('/:id', async (req, res) => {
	try {
		const userToDelete = await User.findByIdAndDelete(req.params.id);
		res.send(`${userToDelete.name} was deleted`);
	}
	catch (error) {
		res.status(500).send('server error');
	}
});

module.exports = router;

Client Side

add static routing

index.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
const db = require('./db');
const port = 5000;
const path = require('path');
const express = require('express');
const app = express();

db.connect();

app.use(express.static(path.join(__dirname, 'public')));
app.use(express.json());
app.get('/ping', (req, res) => res.send('pong'));
app.use('/users', require('./routes/usersRoutes'));

app.listen(port, () => {
    console.log('listen to port', port);
});

public/index.html

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>my client</title>
    <link rel="stylesheet" href="style.css">
    <script src="script.js" defer></script>
</head>

<body>
    <h1>My Awesome Client</h1>
    <pre id="output-test"></pre>
</body>

</html>

public/script.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
const outputEl = document.querySelector('#output-test');

initPage();

async function initPage() {
    const allUsers = await fetchAllUsers();
    outputEl.innerText = JSON.stringify(allUsers, null, 2);
}

async function fetchAllUsers() {
    const res = await fetch('/users');
    return await res.json();
}

Table Element in Webpage

public/index.html

1
2
3
4
5
6
<!-- head element stuff -->

<body>
    <h1>My Awesome Client</h1>
    <table id="users-table"></table>
</body>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
const usersTable = document.querySelector('#users-table');

initPage();

async function initPage() {
    const allUsers = await fetchAllUsers();
    const usersInJSON = JSON.stringify(allUsers, null, 2);
    outputEl.innerText = usersInJSON;
    insertUsersToTable(allUsers);
}

function insertUsersToTable(users) {
    const rows = users.map(u => createUserRow(u));
    usersTable.append(...rows);
}

function createUserRow(user) {
    const userRow = document.createElement('tr');
    const cells = ['name', 'age']
    	.map(p => createTableCell(user[p]));
    userRow.append(...cells);
    return userRow;
}

function createTableCell(text) {
    const cellEl = document.createElement('td');
    cellEl.innerText = text;
    return cellEl;
}

async function fetchAllUsers() {
    const res = await fetch('/users');
    return await res.json();
}