0% found this document useful (0 votes)
34 views99 pages

JavaScript Servers - Module 3 - Noroff Guide - PDF

asd

Uploaded by

stiastr95
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
34 views99 pages

JavaScript Servers - Module 3 - Noroff Guide - PDF

asd

Uploaded by

stiastr95
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

JavaScript Servers - Module 3

Noroff Guide
Table of Contents

Module overview .............................................................................................. 3


Introduction ............................................................................................................................... 3
Learning outcomes ................................................................................................................ 3
3.1. Lesson - Project 1 .................................................................................... 5
Introduction ............................................................................................................................... 5
Learning outcomes ................................................................................................................ 6
Application overview ............................................................................................................ 6
Repository setup ..................................................................................................................... 9
Node setup............................................................................................................................... 12
Restructure - Dependencies........................................................................................... 17
Restructure - Views ............................................................................................................. 24
What did I learn in this lesson? ................................................................................... 26
References ............................................................................................................................... 26
3.1. Lesson task - Project 1 ........................................................................ 27
The task ..................................................................................................................................... 27
3.2. Lesson - Project 2 .................................................................................. 28
Introduction ............................................................................................................................ 28
Learning outcomes ............................................................................................................. 29
Restructure routing (part 1) .......................................................................................... 29
Restructure routing (part 2) .......................................................................................... 33
New typed text - Preparation ........................................................................................ 38
New typed text - Requests .............................................................................................. 42
What did I learn in this lesson? ................................................................................... 45
References ............................................................................................................................... 45
3.2. Lesson task - Project 2 ........................................................................ 46
The task ..................................................................................................................................... 46
3.3. Lesson - Project 3 .................................................................................. 47
Introduction ............................................................................................................................ 47
Learning outcomes ............................................................................................................. 47
Recommendations refactor ............................................................................................ 48
Add and delete recommendations ............................................................................. 53
Portfolio code refactor...................................................................................................... 57
Add new images to the portfolio................................................................................ 64

JavaScript Servers - Module 3 Page i


Delete images from portfolio ....................................................................................... 67
What did I learn in this lesson? ................................................................................... 70
References ............................................................................................................................... 70
3.3. Lesson task - Project 3 ........................................................................ 70
The task ..................................................................................................................................... 70
3.4. Lesson - Project 4 .................................................................................. 71
Introduction ............................................................................................................................ 71
Learning outcomes ............................................................................................................. 72
Login view ................................................................................................................................ 72
Log in to application .......................................................................................................... 79
Requests from user interface ....................................................................................... 87
Adding security to the endpoints .............................................................................. 90
What did I learn in this lesson? ................................................................................... 94
References ............................................................................................................................... 94
3.4. Lesson task - Project 4 ........................................................................ 94
The task ..................................................................................................................................... 94
3.5. Lesson - Self-study ................................................................................ 95
Introduction ............................................................................................................................ 95
Materials ................................................................................................................................... 96
3.5. Lesson task - Self-study ...................................................................... 96
The task ..................................................................................................................................... 96

JavaScript Servers - Module 3 Page ii


Module overview

Introduction
Welcome to Module 3 of JavaScript Servers.

If anything is unclear, check your progression plan and/or contact a tutor on


Discord.

Module structure Estimated workload

3.1. Lesson and task 8 hours


Project 1

3.2. Lesson and task 8 hours


Project 2

3.3. Lesson and task 8 hours


Project 3

3.4. Lesson and task 8 hours


Project 4

3.5. Lesson and task 8 hours


Self-study

Learning outcomes
In this lesson, we are covering the following knowledge learning
outcomes:
 The candidate has knowledge of concepts, processes, and tools used
in node-based JavaScript projects and solutions.

JavaScript Servers - Module 3 Page 3


 The candidate has knowledge of concepts, processes, and tools used
in Node Package Manager-based projects and solutions.
 The candidate has knowledge of concepts, processes, and tools used
in server-based JavaScript solutions.
 The candidate has knowledge of the industry of server-based
JavaScript solutions and is familiar with the field of work.
 The candidate can update their vocational knowledge of server-based
JavaScript solutions.

In this lesson, we are covering the following skill learning outcomes:


 The candidate can apply vocational knowledge of server-based
JavaScript solutions to practical and theoretical situations.
 The candidate masters using nodes to develop, deploy, and maintain
general-purpose JavaScript solutions.
 The candidate masters using Node Package Manager.
 The candidate masters using a server framework for building node-
based web servers.
 The candidate can find information and material relevant to selecting
appropriate node libraries for use in JavaScript solutions.

In this lesson, we are covering the following general competence


learning outcomes:
 The candidate understands the ethical principles that apply when
developing, deploying and maintaining server-based JavaScript
solutions.
 The candidate has developed an ethical attitude concerning the role
of JavaScript server developers and maintainers.
 The candidate can carry out work as a JavaScript server developer and
maintainer.

JavaScript Servers - Module 3 Page 4


3.1. Lesson - Project 1

Introduction

This module will consolidate knowledge from JavaScript servers and restructure the
portfolio app we created a few blocks ago.
In this lesson, we’ll remember the application functionalities taught and create a
new repository with code we’ve already created. Moreover, we’ll set the NodeJS
project for that and initialise the technologies we will use, such as a template
engine.
Furthermore, we’ll look at how to restructure an app. In this lesson, we’ll install all
libraries using NPM instead of downloading them and saving them in the folder.
Moreover, we’ll split the main index file into smaller views using the template
engine.

JavaScript Servers - Module 3 Page 5


Learning outcomes
In this lesson, we are covering the following knowledge learning
outcome:
 The candidate has knowledge of concepts, processes, and tools of
server-based JavaScript solutions.

In this lesson, we are covering the following skill learning outcome:


 The candidate can apply vocational knowledge of server-based
JavaScript solutions to practical and theoretical solutions.

In this lesson, we are covering the following general competence


learning outcome:
 The candidate understands the ethical principles that apply when
developing, deploying and maintaining server-based JavaScript
solutions.

Application overview
In this module, we’ll try to improve the website we’ve already created in the
previous courses. It’s the portfolio website where we can see work created by our
imaginary friend John Doe.

JavaScript Servers - Module 3 Page 6


The website already has six sections, although all sections are on the same page.
We’ll try to restructure the application using the template engine (Embedded
JavaScript). The aim is to have each section in a separate view file instead of
having everything in a single [Link] file.
The application uses several JavaScript libraries, for example, TypedJS, to add
dynamic JavaScript effects. In this lesson, we’ll try to restructure the application
while keeping all the functionalities working. We’ll try substituting JavaScript
libraries downloaded and included in the /lib folder with the NPM equivalent.
If you don’t have code from the project on your computer, you can download it from
the repository. You can download this as the .zip file, extract it (for example, with a
program like 7Zip – a free-to-use tool to extract .zip files), and open the extracted
folder in Visual Studio Code:

JavaScript Servers - Module 3 Page 7


After downloading the repository, extracting it and opening it in VSCode, we can
run the [Link] file to ensure the website works correctly. We should see the
same picture as the one presented at the very beginning:

JavaScript Servers - Module 3 Page 8


Repository setup
We already have the necessary code to start; however, we want to create an
entirely new repository for this project. Let’s go to the main GitHub page,
Login/Sign up, and choose the ‘Create new repository option’:

Let’s name it ‘Portfolio-Node’, make it private for now, and create a standard
README template:

JavaScript Servers - Module 3 Page 9


Click ‘Create Repository’, open Visual Studio Code next and choose the option
‘Clone Repository’.
As your GitHub is already linked to your VSCode, complete the following
steps:
 Choose the repository you just created from the dropdown menu;
 Select the location on our computer where you would like this code to
be cloned to;
 Clone the repository;
 Finally, open that folder in your VSCode.

JavaScript Servers - Module 3 Page 10


We should be able to see only the README template file right now.
To ensure that you are connected to the main branch of the correct repository,
check the bottom left corner of your VSCode:

JavaScript Servers - Module 3 Page 11


Node setup
With our repository ready, it’s time to create a new Node project. Let’s open our
repository folder in VS Code terminal (for example, with CTRL + ‘~’ shortcut on
WindowsOS or by opening a new terminal via the Terminal menu item).

Type the command:


npx express-generator --view=ejs

It will generate a standard ExpressJS project using Embedded JavaScript as the


Template Engine. This command will initialise the NPM project as well. All
necessary dependencies will be included in our [Link] file. We still need to
install them on our local machine with the command:
npm install

This will create a [Link] file and node_modules folder – containing all
files from the dependencies.
You can skip this paragraph if you have no vulnerabilities after running the
command. Although there is a big chance you’ll have one:

JavaScript Servers - Module 3 Page 12


Vulnerabilities are possible security gaps in the packages we use. Often they mean
one of our dependencies is no longer supported by the publisher. In some extreme
cases, they might make our application vulnerable to malicious attacks.
Let’s run the following command to see what is causing this vulnerability:
npm audit

To show an audit report:

By checking the logs, we can see that Express Generator installed the wrong
version of Embedded JavaScript. The installed version (3.1.7 or smaller) is
vulnerable to template injection attacks. This was fixed in the 3.1.8 version. Let’s
install the more recent version with the command:
npm audit fix --force

Now we can see that no vulnerabilities have been found!

JavaScript Servers - Module 3 Page 13


After fixing vulnerabilities, we can try to run the Node application with the
command:
npm start

We can open the link [Link] in the browser and see that the default
application is running locally (meaning on our computer):

We can commit these changes with the comment/message ‘Node Project setup’
and push them to the repository.

JavaScript Servers - Module 3 Page 14


Now, let’s fill our project with code we already have from the repository. Let’s start
by doing the following:
 Clearing our current ‘/public’ folder.
 Delete the ‘/javascripts’, ‘/stylesheets’ and ‘/images’ folders.
 Copy the following folders from the previous repository and place them
there instead:

o lib
o img
o css
o js
Copy the ‘[Link]’ file code and paste this code to the ‘[Link]’ file.
After that, our folder structure should look like this:

JavaScript Servers - Module 3 Page 15


If we run the application as before, we can now see the working application from
the previous repository at [Link]

We can commit these changes as ‘Basic application’ and push them to our
repository:

JavaScript Servers - Module 3 Page 16


Restructure - Dependencies
We currently have a working Node application, but our external libraries are placed
in the /lib folder. This is not ideal, as in the future, these libraries might require
updates, and we’ll have to update them manually by downloading new files and
replacing the current ones in this folder.

This issue can be solved by using NPM packages instead.

JavaScript Servers - Module 3 Page 17


We are using three external libraries:
 Bootstrap;
 JQuery;
 TypedJS.

Let’s start by replacing Bootstrap. First, install Bootstrap with the command:
npm i bootstrap

The ‘npm i’ command is the shorter version of the npm install command. After using
this command, the newest version of Bootstrap should be installed. Now we need
to link it in our ‘[Link]’ file with the command:
[Link]([Link](__dirname +
'/node_modules/bootstrap/dist'));

Preferably, we should place it just after the following line:


[Link]([Link]([Link](__dirname, 'public')));

This line tells the program to look at the Bootstrap/dist folder for the resources. The
last thing we need to do is update how we link these files by deleting the “ ” part
from our paths in the [Link] file:
Before:
<link href="./lib/css/[Link]"
rel="stylesheet">
<!-- ... -->

JavaScript Servers - Module 3 Page 18


<script
src="./lib/js/[Link]"></script>

After:
<link rel="stylesheet" href="css/[Link]"/>
<!-- ... -->
<script src="js/[Link]"></script>

We should also restart the application and ensure that everything works the same
way it was before that change. Having installed the newest version of Bootstrap,
you'll notice that the way in which active buttons behave has changed: selecting a
button in Portfolio doesn’t work correctly, as the first button always remains active:

We can fix that by downgrading Bootstrap to the old 5.0.2 version with the
command:
npm i [email protected]

Buttons should function correctly now:

JavaScript Servers - Module 3 Page 19


Now we can delete the Bootstrap files from the /public/lib” folder as well:

Check if it is working, then commit these changes as ‘Add Bootstrap’ and push
them to the repository:

JavaScript Servers - Module 3 Page 20


The next step is to replace the JQuery library. We can do it in the same way as we
did with Bootstrap. First, let’s install the JQuery package with the command:
npm i jquery

Then include it in [Link]:


[Link]([Link](__dirname +
'/node_modules/jquery/dist/'));

and replace the value in [Link]:


Before:
<script src="./lib/js/[Link]"></script>

After:
<script src="[Link]"></script>

JavaScript Servers - Module 3 Page 21


We can remove the jQuery file in /public/lib folder, check if the application is
working, and commit the changes:

The last library is TypedJS.


We need to install it with the command:
npm i [Link]@2.012

Include it in ‘[Link]’ as usual. Although this time, the path will be different, the files
we are looking for are in the ‘/lib’ folder, not ‘/dist’. We can check that by opening
the ‘/node_modules/[Link]’ folder in the explorer:

JavaScript Servers - Module 3 Page 22


[Link]([Link](__dirname +
'/node_modules/[Link]/lib'));

We also need to update the [Link] file:


Before:
<script src="./lib/js/[Link]"></script>

After:
<script src="[Link]"></script>

Now we can delete the ‘[Link]’ file in the ‘/public/lib’ library and completely delete
the entire folder (as it should be empty now).
Let’s ensure that the application is working as it was (in this case, we should
ensure the front page with the ‘Welcome I am …’ text is working). If everything is
correct, commit the changes as ‘Add [Link]’:

JavaScript Servers - Module 3 Page 23


Restructure - Views
So far, our entire user interface is placed in one file – ‘[Link]’. Let’s split it into
smaller parts, so every independent section is in its own file.
For now, we won’t be changing routing, only how the code is structured.
Let’s create a /partial folder in the /views folder. In this folder, create files:
 [Link] – here we will place the nav element;
 [Link] - here we will place the header element;
 [Link] - here we will place the about section element;
 [Link] - here we will place the services section element;
 [Link] - here we will place the recommendations section
element;
 [Link] - here we will place the portfolio section element;
 [Link] - here we will place the contact section element.

Cut the code fragments from the ‘[Link]’ file and paste them to the following
files. After that, include the files in ‘[Link]’ so its final form is as follows:
[Link]:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Portfolio</title>
<link rel="stylesheet"
href="[Link]
icons/1.9.1/font/[Link]">
<link rel="stylesheet" href="css/[Link]"/>
<link href="./css/[Link]" rel="stylesheet">
<link href="./css/[Link]" rel="stylesheet">
<link href="./css/[Link]" rel="stylesheet">
<link href="./css/[Link]" rel="stylesheet">
<link href="./css/[Link]" rel="stylesheet">
<link href="./css/[Link]" rel="stylesheet">
<link href="./css/[Link]" rel="stylesheet">
</head>
<body class="position-relative" data-bs-spy="scroll">

JavaScript Servers - Module 3 Page 24


<%- include('./partials/[Link]') %>
<div data-spy="scroll" data-target="#navbar" data-
offset="0">
<%- include('./partials/[Link]') %>
<%- include('./partials/[Link]') %>
<%- include('./partials/[Link]')
%>
<%- include('./partials/[Link]')
%>
<%- include('./partials/[Link]')
%>
<%- include('./partials/[Link]') %>
</div>
<script src="./[Link]"></script>
<script src="./js/[Link]"></script>
<script src="./[Link]"></script>
<script src="./js/[Link]"></script>
<script src="./js/[Link]"></script>
</body>
</html>

Make sure the application is working. Then commit the changes as ‘View
restructure’:

JavaScript Servers - Module 3 Page 25


What did I learn in this lesson?
This lesson provided the following insights:
 How to restructure existing application into Express application.
 How to change local libraries to NPM packages.
 How to split one big view into smaller parts.

References
[Link] (n.d.). Express Fast, unopinionated, minimalist web framework for
[Link]. Available at: [Link] 9 January 2023).
GitHub, Inc. (2023). Bartektrr/Portfolio. Available at:
[Link] 9 January 2023).
7-Zip (2022). 7-Zip. Available at: [Link] (Accessed: 9 January
2023).

JavaScript Servers - Module 3 Page 26


3.1. Lesson task - Project 1

The task
In this lesson, we learnt how to restructure an existing application, into an Express
website.

Part 1

While splitting views into smaller parts, we mainly took care of portfolio
sections. Right now, code, including stylesheets and libraries, is taking up a
huge part of code in the ‘[Link]’ file. Create two more partials:
 [Link]
 [Link]

and export code from ‘[Link]’ into these partials. Notice that you will need to
change the path to files, as the ‘/partials’ folder is on the other level than the ‘/view’
folder.
Check whether the application is working and commit the changes to your
repository.
Source code: Click here to reveal [Link].
Source code: Click here to reveal [Link].
Source code: Click here to reveal [Link].

Part 2

We are still using Bootstrap Icons with the CDN:


<link rel="stylesheet"
href="[Link]
icons/1.9.1/font/[Link]">

Install Bootstrap with NPM instead.


Commit the changes to your repository.

JavaScript Servers - Module 3 Page 27


Source code: Click here to reveal [Link].
Source code: Click here to reveal [Link] (code added).

3.2. Lesson - Project 2

Introduction

We’ve already restructured our Portfolio application into the ExpressJS project. In
this section, we’ll continue improving it by splitting all sections into separate
endpoints.

An endpoint is a digital location where our API receives requests about a specific
resource. Endpoints are usually specified as URLs. That’s how the most popular
web applications are built; for example, when visiting a pizzeria’s website, we can
directly go to the [Link]/menu link if we are interested
in the menu. We can access it directly from Google as well with only one click.

For comparison, we could also select an element on the navbar or scroll down, but
this takes more time and requires more effort from the user.
Creating endpoints also makes request handling much clearer. Each endpoint will
have its own router file, where we will have all request handlers.

JavaScript Servers - Module 3 Page 28


In this lesson, besides creating a simple GET request, we’ll add new functionality
using the POST request. To make this possible, we’ll need to change the way data
is stored and accessed from the views.

Learning outcomes
In this lesson, we are covering the following knowledge learning
outcome:
 The candidate has knowledge of concepts, processes, and tools of
server-based JavaScript solutions.

In this lesson, we are covering the following skill learning outcomes:


 The candidate can apply vocational knowledge of server-based
JavaScript solutions to practical and theoretical solutions.
 The candidate masters the use of a server framework for building
Node based web servers.

In this lesson, we are covering the following general competence


learning outcome:
 The candidate understands the ethical principles that apply when
developing, deploying and maintaining server-based JavaScript
solutions.

Restructure routing (part 1)


In the next two chapters, we’ll change how our application looks. Right now, all
content is visible on the main page. We want to split it into several endpoints so
each section has its own page. We want the navbar to be always visible, as we’ll
use it to navigate to the other endpoints.

JavaScript Servers - Module 3 Page 29


For each section we have, let’s create a new file in the routes folder:
 [Link]
 [Link]
 [Link]
 [Link]
 [Link]
 [Link]

Also create the views that will be used by these routers (in the views folder):
 [Link]
 [Link]
 [Link]
 [Link]
 [Link]
 [Link]

Fill all the view files with code from the ‘[Link]’ file reduced by the other section
includes. For example, the ‘[Link]’ view file should look like this:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Portfolio</title>
<%- include('./partials/[Link]') %>
</head>
<body class="position-relative" data-bs-spy="scroll">
<%- include('./partials/[Link]') %>
<div data-spy="scroll" data-target="#navbar" data-
offset="0">
<%- include('./partials/[Link]') %>
</div>
<%- include('./partials/[Link]') %>
</body>
</html>

JavaScript Servers - Module 3 Page 30


Fill all the router files with code similar to that of the ‘[Link]’ file.
The ‘[Link]’ file should look like this:
var express = require('express');
var router = [Link]();

/* GET home page. */


[Link]('/', function(req, res, next) {
[Link]('home');
});

[Link] = router;

The other files should follow the same structure, but instead of the
‘[Link](‘home’)’ line, they should have the name of the corresponding section
instead.
e.g., ‘[Link](‘section name’)’ - In this line, we are returning a view we created
earlier; therefore, ‘[Link](‘home’)’ returns the ‘[Link]’ file to the client.
The last thing we need to do is to use the created routers in the ‘[Link] file’:
Let’s create variables with exported routers (in the place where indexRouter is
created):
[Link]:
var indexRouter = require('./routes/index');
var homeRouter = require('./routes/home');
var aboutRouter = require('./routes/about');
var servicesRouter = require('./routes/services');
var recommendationsRouter =
require('./routes/recommendations');
var portfolioRouter = require('./routes/portfolio');
var contactRouter = require('./routes/contact');

And add them to the application with the [Link]() function (in the same place
where indexRouter is added):
[Link]:

JavaScript Servers - Module 3 Page 31


[Link]('/', indexRouter);
[Link]('/home', homeRouter);
[Link]('/about', aboutRouter);
[Link]('/services', servicesRouter);
[Link]('/recommendations', recommendationsRouter);
[Link]('/portfolio', portfolioRouter);
[Link]('/contact', contactRouter);

Our code would still work if we included all GET request handlers in the [Link]
router file. We created separate router files to keep our code structure clear.

Each section will have a few handlers, storing everything in one file. While
theoretically working, it makes it very hard to find the one handler we want to
change or debug.
Now we can run the application and check whether the newly created endpoints
are working correctly, for example, by entering the [Link]
link:

We can see there are still some style issues, but the page functions correctly and
shows the proper content. However, the navbar is not working correctly yet. We’ll
try to address these issues in the next section. Now we can commit changes to the
repository as the ‘Add basic routing’:

JavaScript Servers - Module 3 Page 32


Restructure routing (part 2)
Our routing works almost as intended, besides the navbar still not working correctly
and the few style issues. In this section, we’ll try to find all the bugs and address
them.
The first bug we have is the navbar directing us to the wrong paths – for example,
after clicking on the About tab, we will be moved to [Link] We
can easily change that by modifying the ‘/views/partials/[Link]’ file. Here, we
must change all the hrefs to ‘/content’ instead of ‘#content', for example:
Before:
<a class="nav-link" href="#about">About</a>

JavaScript Servers - Module 3 Page 33


After:
<a class="nav-link" href="/about">About</a>

To make the logo point to the main page where we can see all the content as a
scrollable website, change the href to the following:
<a class="navbar-brand" href="/">The cake master</a>

After that, the navbar should work accurately. The other issue is that our paddings
are not working correctly. They were created for the one scrollable page design.

We still want to keep our main [Link] page working, so we should


change the header and script sections in each new view.
Let’s go to the ‘/public/css/’ folder and create a new folder for each
section:
 home
 about
 services
 recommendations
 portfolio
 contact

In the home section, we have a blank space at the bottom:

JavaScript Servers - Module 3 Page 34


There are two stylesheets connected to the home section:
1. [Link]
2. [Link]

Let’s copy them to the new ‘public/css/home’ folder.


The style causing this blank area is inside the [Link] file:
header {
padding-top: 50px;
}

After looking at the file, this styling is entirely unnecessary. The page should work if
we completely remove it, so let’s do it.
Change the path to the background image in the ‘[Link]’ file:
background-image: linear-gradient(rgba(0, 0, 0, 0.5),
rgba(0, 0, 0, 0.5)),
url("../../img/[Link]");

Let’s open the ‘/views/[Link]’ file and replace this code:


<%- include('./partials/[Link]') %>

JavaScript Servers - Module 3 Page 35


With:
<link rel="stylesheet" href="../font/bootstrap-
[Link]">
<link rel="stylesheet"
href="../css/[Link]"/>
<link href="../css/home/[Link]" rel="stylesheet">

Let’s also move to the ‘About’ section.


Put:
 [Link]
 [Link]

into the created ‘about’ CSS folder.


Now you’ll notice the issue is that the top text is covered with the navbar:

We can solve it by setting the padding-top property of the section. Let’s replace all
the code inside the ‘[Link]’ file with the following:
section {
padding-top: 50px;
}

Now you should link the new CSS files in the ‘/views/[Link]’ file:
Before:
<%- include('./partials/[Link]') %>

JavaScript Servers - Module 3 Page 36


After:
<link rel="stylesheet" href="../font/bootstrap-
[Link]">
<link rel="stylesheet"
href="../css/[Link]"/>
<link href="../css/about/[Link]"
rel="stylesheet">
<link href="../css/about/[Link]" rel="stylesheet">

The navbar should now display correctly:

We can see the same issue in the next sections, which should be repaired in the
same way.
After fixing all the styling mentioned, commit the changes to the repository as
‘Routing style fixes’:

JavaScript Servers - Module 3 Page 37


New typed text - Preparation
We already have our routing working. In the following two chapters, we’ll add new
functionality, which adds new text to display with TypedJS. In this chapter, we’ll
refactor our code, and in the next one, we’ll create new endpoints to handle POST
requests from the user.

JavaScript Servers - Module 3 Page 38


So far, these introductory sentences (for example, ‘I am a Man with Passion’,
specifically, the ‘a Man with Passion’ part) are hardcoded in the ‘/public/js/[Link]’
file. Let’s create the ‘data’ folder at the same level as the ‘public’ and ‘routes’
folders. Create the ‘[Link]’ file in there with this array:
["John Doe", "The Cake Master", "a Confectioner","a Man with
Passion"]

We’ll need to read the file before the application starts and pass the data to the
view. Notice that the current file responsible for this functionality (/public/js/[Link]) is
the front-end file; it has no access to the server files. Because of that, we can’t just
read data in the ‘public/js/[Link]’ file. We need our server to read the data and then
send it to the front-end file.
To do that, we need to change how this functionality works on the home and main
pages. Let’s open the ‘[Link]’ file from the router folder. Let’s read the file on the
GET request and pass the read array to the view:
var express = require('express');
var router = [Link]();
const fs = require("fs")
const path = require("path")

/* GET home page. */


[Link]('/', function(req, res, next) {

JavaScript Servers - Module 3 Page 39


let data = [Link]([Link](__dirname,
"../data/[Link]"));
[Link]('home', { array: [Link](data)});
});

[Link] = router;

Read data is in JSON format; therefore, we first need to convert it to a JavaScript


object or array using [Link]() function.
Let’s do the same thing in the [Link] file:
var express = require('express');
var router = [Link]();
const fs = require("fs")
const path = require("path")

/* GET home page. */


[Link]('/', function(req, res, next) {
let data = [Link]([Link](__dirname,
"../data/[Link]"));
[Link]('index', { title: 'Express' , array:
[Link](data)});
});

[Link] = router;

Let’s remove the /public/js/[Link] file dependency from /views/partials/[Link]


file:
<script src="../[Link]"></script>
<script src="../js/[Link]"></script>
<script src="../[Link]"></script>
<script src="../js/[Link]"></script>

We need to create a script using the read data. Let’s add the ‘/public/js/[Link]’
content to the ‘/views/[Link]’ and ‘/views/[Link]’ views while changing the
hardcoded array to read data.

JavaScript Servers - Module 3 Page 40


To pass an array to JavaScript with EJS, we need to use the [Link]()
function. The included scripts part of the views should now look like this:
<%- include('./partials/[Link]') %>
<script>
var typed = new Typed(".aboutMe", {
strings: <%- [Link](array) %> ,
smartBackspace: true,
typeSpeed: 100,
backSpeed: 100,
loop: true,
loopCount: Infinity,
startDelay: 1000
});
</script>

Now we can delete the /public/js/[Link] file as well, as it will no longer be needed.
Make sure that the application is working properly and commit changes as
‘Refactor [Link] code’:

JavaScript Servers - Module 3 Page 41


New typed text - Requests
Our code handling typed text got refactored, and we stored the strings in a
separate file. In programming, by refactoring, we understand the process of
changing the code to increase its quality while keeping its functionality the same.

Thanks to this, we can change the content just by modifying the


‘[Link]’ file. In this section, we’ll create a handler for the /home
POST request. This request will allow us to add new introduction sentences. We’ll
include them in the request’s body.

Next, we’ll append this text to the [Link] file. Thanks to that, our
home page displays more introduction sentences!
We’ll use the body parser to get the request’s JSON body more easily by adding
these two lines on the top of the [Link] file:

JavaScript Servers - Module 3 Page 42


var bodyParser = require('body-parser')
var jsonParser = [Link]()

To handle the post, we can use the [Link]() method. We’ll use the same path
as with the GET request. As the second parameter, we’ll pass just included JSON
parser.
First, we’ll read the [Link] file synchronously with the
readFileSync() method. We’ll convert the data and append the element from the
request’s body to the array.
Then we will save the result to the same file ([Link]).
The expected request should have the following structure:
{
"newText": "value"
}

The final code handling request should look like this:


[Link]('/', jsonParser, function(req, res, next) {
let rawdata = [Link]([Link](__dirname,
"../data/[Link]"));
let array = [Link](rawdata);
const newArray = [Link]([[Link]])
[Link]([Link](__dirname,
"../data/[Link]"), [Link](newArray));
[Link]();
});

Now we can test it with the use of Postman.


Send the following request:

JavaScript Servers - Module 3 Page 43


We can see that our [Link] file was changed:

Now, let’s run the application. We should be able to notice the new text:

If everything is working, commit changes to the repository as ‘Add handling new


introductions’:

JavaScript Servers - Module 3 Page 44


What did I learn in this lesson?
This lesson provided the following insights:
 How to split one big scrollable page into smaller parts.
 How to find and fix style bugs connected to code refactor.
 How to use POST requests to change displayed data on our application.

References
[Link] (n.d.). Express Fast, unopinionated, minimalist web framework for
[Link]. Available at: [Link] 9 January 2023).

JavaScript Servers - Module 3 Page 45


3.2. Lesson task - Project 2

The task
This lesson taught us how to split our content into smaller parts with separate
endpoints. We also added a few new functionalities to the application.

Right now, we can add new sentences introducing John Doe. But, so far, we are
unable to remove existing ones. Enable the user to do that with a DELETE request
to the /home endpoint. You can handle the DELETE request similarly to the POST
request (with the [Link]() method).
The program should be able to handle the following request (text ‘also a good
programmer!’ should be removed from the introductionsArray):

If the text doesn’t exist in the array, don’t change anything.

JavaScript Servers - Module 3 Page 46


3.3. Lesson - Project 3

Introduction

In this lesson, we’ll continue developing new functionalities in our application. First,
we’ll focus on the Recommendations section. Here we’ll handle adding new
recommendations and removing existing ones.
The next part of this lesson will focus on the Portfolio section. We’ll develop an
option to add new pictures to the collection and remove existing ones. So far, all
images are stored on the front-end, so we’ll first need to refactor our code.

Learning outcomes
In this lesson, we are covering the following knowledge learning
outcome:
 The candidate has knowledge of concepts, processes, and tools of
server-based JavaScript solutions.

JavaScript Servers - Module 3 Page 47


In this lesson, we are covering the following skill learning outcomes:
 The candidate can apply vocational knowledge of server-based
JavaScript solutions to practical and theoretical solutions.
 The candidate masters the use of a server framework for building
Node based web servers.

In this lesson, we are covering the following general competence


learning outcome:
 The candidate understands the ethical principles that apply when
developing, deploying and maintaining server-based JavaScript
solutions.

Recommendations refactor
In this section, we’ll enable users to add new recommendations with the
POST request. The recommendation consists of four parts:
 avatar;
 name;
 role;
 description.

In this section, we’ll only use the three avatars already in our images folder,
keeping them at the front-end. The number of chosen avatars and the rest of the
information will be kept on the back-end.
Currently, our recommendations are hardcoded in the
‘/views/partial/[Link]’ view. We need to move them into JSON if we
want to add new recommendations. Let’s create the ‘[Link]’ file in
our data folder:

JavaScript Servers - Module 3 Page 48


And place all hardcoded data from the /views/partial/[Link] file into
this new JSON file:
[
{
"avatar": 1,
"name": "Maria Kate",
"role": "Mom",
"description": "I ordered a cake for my son's
birthday. It was so delicious, that people asked me where I
got such a cake. I will definitely order more cakes in the
future!"
},
{
"avatar": 2,
"name": "Mark Stones",
"role": "Husband",
"description": "A month ago we had the wedding
anniversary. I decided to order the cake from the cake
master. I was more than satisfied. My wife said that she has
never ate such a good cake. I can heavily recommend the cake
master!"
},
{
"avatar": 3,
"name": "Barbara Smith",
"role": "Teacher",
"description": "Recently we were organizing the
school party. As this event was special, we decided that
served meals also need to be special. Because of that, we
ordered cakes from the cake master. It was the first time I
saw every student eating it without whining! There was no
pieces left. I will definitely order cakes from the cake
masters again in the future!"
}
]

Now open the [Link] router file, read the file and pass it to the view:

JavaScript Servers - Module 3 Page 49


var express = require('express');
var router = [Link]();
const fs = require("fs")
const path = require("path")

/* GET home page. */


[Link]('/', function(req, res, next) {
let data = [Link]([Link](__dirname,
"../data/[Link]"));
[Link]('recommendations', { data: [Link](data)
});
});

[Link] = router;

Open the ‘/views/partials/[Link]’ file. Let’s modify it to use the read


data. To do that, we should print all items in the data array (the one we read in the
router file and passed to the view) with a loop (for example, forEach()). Remember
to use the ‘<%=’ EJS tag to output value to the HTML template (read more at EJS
documentation).
<section id="recommendations">
<div class="p-5 text-center">
<h2>Testimony</h2>
<p class="mb-5">What people say about us.</p>
<div id="carouselExampleControls" class="container
carousel slide" data-bs-ride="carousel">
<div class="carousel-inner">
<% [Link](function(recommendation, index){ %>
<div class="<%= index === 0 ? "carousel-item
active": "carousel-item" %>">
<img class="rounded-circle shadow-1-strong mb-
4"
src=<%='./img/avatar' + [Link] +
'.jpg'%> alt="avatar"
style="width: 150px;" />
<div class="row d-flex justify-content-center">
<div class="col-lg-8">
<h5 class="mb-

JavaScript Servers - Module 3 Page 50


3"><%=[Link]%></h5>
<p><%=[Link]%></p>
<p class="text-muted">
<i class="bi bi-quote pe-2"></i>
<%=[Link]%>
</p>
</div>
</div>
</div>
<% }); %>
<button class="carousel-control-prev" type="button"
data-bs-target="#carouselExampleControls"
data-bs-slide="prev">
<span class="carousel-control-prev-icon" aria-
hidden="true"></span>
<span class="visually-hidden">Previous</span>
</button>
<button class="carousel-control-next" type="button"
data-bs-target="#carouselExampleControls"
data-bs-slide="next">
<span class="carousel-control-next-icon" aria-
hidden="true"></span>
<span class="visually-hidden">Next</span>
</button>
</div>
</div>
</section>

We use the ternary operator and the current item’s index to make the first element
active. In the Bootstrap carousel, the active item is displayed first after we enter the
page. We replaced all hardcoded values with read data, so now we need to pass
the data from the ‘/view/[Link]’ to
‘/view/partials/[Link]’.
The ‘/view/[Link]’ should now look as follows:
<%- include('./partials/[Link]', {data:
data}) %>

JavaScript Servers - Module 3 Page 51


We can run the application and make sure the Recommendation tab is working
correctly:

However, we still need to fix the main page. Right now, it throws the error because
we changed the ‘/view/partials/[Link]’, but we didn’t make any
changes in the ‘[Link]’ router file and ‘[Link]' view (‘[Link]’ file uses
‘[Link]’ partial):

JavaScript Servers - Module 3 Page 52


We can fix that by modifying these files in the same way we modified the
‘[Link]' and '/views/[Link]’ files:
1. Read [Link] file in [Link].
2. Pass read data to [Link] view.
3. In [Link] pass this data to the [Link] partial

Make these changes and commit changes to the repository as ‘Refactor


recommendations’:

Add and delete recommendations


After refactoring the Recommendations code, we can quickly handle POST and
DELETE requests. Both cases will be analogous to handling text updates from the
previous lesson.
We need to include the parser in the recommendations router file:
var bodyParser = require('body-parser')
var jsonParser = [Link]()

JavaScript Servers - Module 3 Page 53


Then we can use it to handle the POST request. We only want to add a new
recommendation if the person giving it has not given one already. Because of that,
we’ll filter the data before adding the data from the request:
[Link]('/', jsonParser, function(req, res, next) {
let rawdata = [Link]([Link](__dirname,
"../data/[Link]"));
let recommendationsArray = [Link](rawdata);
if([Link](x => [Link] ===
[Link]).length == 0) {
const newArray = [Link]([[Link]])
[Link]([Link](__dirname,
"../data/[Link]"), [Link](newArray));
}
[Link]();
});

We can send a request with Postman:

And see that data was properly updated, either by looking at the
[Link] file:

JavaScript Servers - Module 3 Page 54


or by looking at the Recommendations section:

Now let’s handle the DELETE request. We want the user to send the name of the
person whose recommendation should be deleted. If there is such a
recommendation, we delete it - if not, we’ll ignore the request.
The expected request’s body should be in the following form:
{
"name": "Barbara Stones"
}

In the DELETE request handler, we’ll filter the current recommendations array,
whether or not it contains recommendations from the specified person. If the filtered
array differs from the one before filtering, we’ll save the filtered one to the
‘/data/[Link]’ file.

Note that we could always save the filtered array without checking differences, and
the application would work the same way. However, the process of saving the file
takes much more time than filtering the array once. Operations of opening a file,
writing to the file and saving it take some time. Filtering data we already read is
much quicker.
Our DELETE request’s handler will be very similar to the POST handler:
[Link]('/', jsonParser, function(req, res, next) {
let rawdata = [Link]([Link](__dirname,
"../data/[Link]"));

JavaScript Servers - Module 3 Page 55


let recommendationsArray = [Link](rawdata);
const newArray = [Link](x => [Link]
!== [Link])
if ([Link] !== [Link] ) {
[Link]([Link](__dirname,
"../data/[Link]"), [Link](newArray));
}
[Link]();
});

Now we can use Postman to ensure everything works correctly.


After sending the request:

The recommendation we just added no longer exists:

We can now commit changes as ‘Add POST and DELETE recommendations


handlers’:

JavaScript Servers - Module 3 Page 56


Portfolio code refactor
In this section, we need to refactor code from the Portfolio section so that images
are stored on the back-end, not the front-end. In the previous example, users could
choose one of the three avatars. Now, we want to make them select any images
they want and prescribe them to one of the four categories.
Let’s create a ‘/img’ folder inside the ‘/data’ folder.
Copy all cake images from ‘/public/img/’ to new ‘/data/img’.
Create a ‘[Link]’ file with all the data that was hardcoded in the
‘/views/partials/[Link]’ file:
[
{
"name": "wedding_cake.jpg",

JavaScript Servers - Module 3 Page 57


"alt": "Wedding",
"category": "wedding",
"header": "Wedding cake for Mark & Emily",
"description": "Emily said she loves flowers, she
loved the cake even more."
},
{
"name": "wedding_cake2.jpg",
"alt": "Wedding 2",
"category": "wedding",
"header": "Wedding cake for John & Barbara",
"description": "The newlyweds said they like
minimalistic style."
},
{
"name": "wedding_cake3.jpg",
"alt": "Wedding 3",
"category": "wedding",
"header": "Wedding cake for Steven & Sarah",
"description": "Steven and Sarah invited many guests,
so they wanted to be sure that everyone can taste the wedding
cake."
},
{
"name": "christmas_cake.jpeg",
"alt": "Christmas",
"category": "christmas",
"header": "Last Christmas",
"description": "With this cake you can feel the
spirit of the Christmas."
},
{
"name": "christmas_cake2.jpeg",
"alt": "Christmas 2",
"category": "christmas",
"header": "Classy Christmas",
"description": "Spend your Christmas with style and
taste this modern-looking cake!"
},

JavaScript Servers - Module 3 Page 58


{
"name": "birthday_cake.jpg",
"alt": "Birthday",
"category": "birthday",
"header": "Cream birthday cake",
"description": "Make a wish before tasting this
delicious cake!"
},
{
"name": "birthday_cake2.jpg",
"alt": "Birthday 2",
"category": "birthday",
"header": "Raspberry birthday cake",
"description": "Small Alexandra celebrated her third
birthday with this delicious cake."
},
{
"name": "anniversary_cake.jpeg",
"alt": "Anniversary 1",
"category": "anniversary",
"header": "50th wedding anniversary",
"description": "Harry and Margaret celebrated their
50th wedding anniversary with style."
},
{
"name": "anniversary_cake2.jpeg",
"alt": "Anniversary 2",
"category": "anniversary",
"header": "Company's 50th anniversary",
"description": "The big company celebrated its 50th
anniversary with this classy cake!"
}
]

Next, let’s open the ‘/views/partials/portfolio. ejs’ file. As in the previous sections,
we can easily adapt this code to display JSON data in a loop. The only problem is
the front-end image link, which we no longer want to use.

JavaScript Servers - Module 3 Page 59


For now, let’s use one of the front-end images as a placeholder (we will solve this
later).
Our /views/partials/[Link] file should like this:
<section id="portfolio">
<div class="container">
<div class="row">
<div class="col mb-5 text-center">
<h2>Portfolio</h2>
<p>The cakes I already baked for my clients.</p>
</div>
</div>
<div class="row">
<div class="col-xs-12 mx-auto mb-5">
<button class="btn active"
onclick="filterSelection('all')"> Show all</button>
<button class="btn"
onclick="filterSelection('wedding')">Wedding cakes</button>
<button class="btn"
onclick="filterSelection('christmas')"> Christmas
cakes</button>
<button class="btn"
onclick="filterSelection('birthday')"> Birthday
cakes</button>
<button class="btn"
onclick="filterSelection('anniversary')"> Anniversary
cakes</button>
</div>
</div>
<div class="row grid">
<% [Link](function(cake){ %>
<div class="hide col-lg-4 col-md-6 col-sm-12
<%=[Link]%>">
<div class="text-center">
<img class="mb-3" src="./img/wedding_cake.jpg"
alt="<%=[Link]%>" style="width:100%">
<h4><%=[Link]%></h4>
<p><%=[Link]%></p>
</div>
</div>

JavaScript Servers - Module 3 Page 60


<% });%>
</div>
</section>

First, open the [Link] router. Read the ‘[Link]’ file and pass it to the
portfolio view – the same way we already did a few times earlier:
[Link]('/', function(req, res, next) {
let data = [Link]([Link](__dirname,
"../data/[Link]"));
[Link]('portfolio', { cakes: [Link](data)});
});

Now pass data from the portfolio view to the portfolio partial:
/views/[Link] looks as follows:
<%- include('./partials/[Link]', {cakes: cakes})
%>

So far, our portfolio page should work and display data from the [Link],
despite the repeated image:

The last thing we need to do is to update the picture. We need to create a second
server that will serve images. Let’s create the ‘[Link]’ file inside the ‘/bin’
folder:

JavaScript Servers - Module 3 Page 61


const express = require('express');
const path = require('path');

const app = express();


const PORT = 8080;
[Link]('/images', [Link]([Link](__dirname,
'../data/img')));

[Link](PORT, () => {
[Link](`Running server on PORT ${PORT}...`);
})

Run this server with


node bin/imagesServer

and try to access the endpoint: [Link]


We should see the image:

JavaScript Servers - Module 3 Page 62


This server will run simultaneously with our application but on a different port
(8080). This way, we can access the images from this place.
Change the image declaration in the ‘[Link]’/views/partials/[Link]’
file to:
<img class="mb-3"
src="[Link]
alt="<%=[Link]%>" style="width:100%">

We access the file here from our images server. Without turning off the image
server, open the VSCode terminal. Click the plus icon in the upright corner:

Run the application in the new terminal. Now both servers are running, and we
should be able to see the correct portfolio:

However, the main page is not working correctly:

JavaScript Servers - Module 3 Page 63


To fix this issue, all you need to do is to adapt the ‘[Link]’ and ‘[Link]’ files in
the same way the portfolio files were adapted before.
After that is done, commit the changes as Portfolio refactor:

Add new images to the portfolio


In this section, we’ll handle adding new images to the portfolio. We expect the user
to send the URL of the image to add, as well as all other necessary data (as stated
in [Link]).

Let’s look at an example of an expected request:


{
"url": "[Link]

JavaScript Servers - Module 3 Page 64


"name": "[Link]",
"alt": "google 1",
"category": "anniversary",
"header": "Google'd!",
"description": "It's not a cake, it's Google!"
}

We will use the ‘Request package’ to download images easier from its URL. Let’s
install it with the command:
npm install request

After installation, add it to the [Link] file and create a function downloading the
file:
var request = require('request');

//download image to the server:


var download = function(url, filename, callback){
[Link](url, function(err, res, body){
request(url).pipe([Link]([Link](__dir
name, '../data/img/'+ filename))).on('close', callback);
});
};

We do the request to the URL, download the image with the write stream and save
it at ‘/data/img’ folder.
Let’s create a POST request handler as usual, but with the use of the new
download() function, to download the image:
[Link]('/', jsonParser, function(req, res, next) {
let rawdata = [Link]([Link](__dirname,
"../data/[Link]"));
let portfoliosArray = [Link](rawdata);
if([Link](x => [Link] ===
[Link]).length == 0) {
download([Link], [Link], function(){
[Link]('done');

JavaScript Servers - Module 3 Page 65


});
const newArray = [Link]([[Link]])
[Link]([Link](__dirname,
"../data/[Link]"), [Link](newArray));
}
[Link]();
});

We save the image only if there is no image with that specified name.
To test it, run the application and send the request:

We can see that the ‘[Link]’ file was created in the data folder. Moreover, it’s
visible in the portfolio, in ‘all’ and ‘anniversary’ categories:

JavaScript Servers - Module 3 Page 66


Now commit changes to the repository as: ‘Add POST handler for portfolio’.

Delete images from portfolio


We want users to be able to delete pictures from portfolios as well. To do that, they
need to send a request with the name of the image to delete. The image and all the
information connected to that image from the ‘[Link]’ file should be
permanently deleted.
We will be expecting a DELETE request from the user containing the name
property, for example:

JavaScript Servers - Module 3 Page 67


{
"name": "[Link]"
}

We will modify the ‘[Link]’ file in the same way as in the previous chapters.
To delete an image (or any file in general), we can use the file system unlink()
method. It deletes a file of the provided path. Let’s implement the DELETE handler:
[Link]('/', jsonParser, function(req, res, next) {
let rawdata = [Link]([Link](__dirname,
"../data/[Link]"));
let portfoliosArray = [Link](rawdata);
const newArray = [Link](x => [Link] !==
[Link])
if([Link] !== [Link]) {
[Link]([Link](__dirname, '../data/img/'+
[Link]), () => {
[Link]([Link] + " deleted!");
});
[Link]([Link](__dirname,
"../data/[Link]"), [Link](newArray));
}
[Link]();
});

We can send the following request:

JavaScript Servers - Module 3 Page 68


This will delete the Google image we added before. After that, we can see that it
has disappeared from the ‘/data/img’ folder:

And it is no longer visible on the portfolio page:

Finally commit all changes to the repository as ‘Add DELETE handler for portfolio’:

JavaScript Servers - Module 3 Page 69


What did I learn in this lesson?
This lesson provided the following insights:
 How to refactor the front-end application into the back-end application.
 How to create server hosting images.
 How to store, add and delete files on the server.

References
[Link] (n.d.). Express Fast, unopinionated, minimalist web framework for
[Link]. Available at: [Link] 9 January 2023).
EJS (n.d.). Embedded JavaScript templating. Available at: [Link]
9 January 2023).

3.3. Lesson task - Project 3

The task
In this lesson, we implemented new functionalities in two sections of our
application. However, they are not properly validated; for example, someone might
provide incomplete data in the request or complete but with unmatching types.

JavaScript Servers - Module 3 Page 70


Think of and create validation of data in requests created in this lesson
(recommendations and portfolio sections).
Possible solution: Click here to reveal portfolio validation.
Possible solution: Click here to reveal recommendations validation.

3.4. Lesson - Project 4

Introduction

We already have a working application with new functionalities. However, we don’t


necessarily want everyone to be able to modify our website, as is currently the
case. In this module, we’ll create authentication using the PassportJS package.
First, we’ll create a login view and add it to our navbar. Then we’ll install
PassportJS and use its local authentication strategy. The user’s data will be stored
in a separate file in the data folder.
Finally, we’ll link some of the implemented functionalities to our user interface and
make it visible only to logged-in users. For example, they can delete images from
the portfolio with one click only instead of creating requests from Postman.

JavaScript Servers - Module 3 Page 71


Learning outcomes
In this lesson, we are covering the following knowledge learning
outcome:
 The candidate has knowledge of concepts, processes, and tools of
server-based JavaScript solutions.

In this lesson, we are covering the following skill learning outcomes:


 The candidate can apply vocational knowledge of server-based
JavaScript solutions to practical and theoretical solutions.
 The candidate masters the use of a server framework for building
Node based web servers.

In this lesson, we are covering the following general competence


learning outcome:
 The candidate understands the ethical principles that apply when
developing, deploying and maintaining server-based JavaScript
solutions.

Login view
In this section, we’ll create the necessary user interface so that users can log in to
our application. We’ll base this interface on the login view used in the lesson about
PassportJS. You don’t need to remember any code from that lesson, as all the new
files will be shown here.
First, we want to create a new section with the login view. The view used in the
lesson mentioned above looked like this:

JavaScript Servers - Module 3 Page 72


This view would suit our needs exactly!
Let’s create the login folder in the ‘/public/css’ folder and copy the ‘[Link]’ file
from the PassportJS lesson (or from the pasted code below), so we can use these
styles:
[Link]:
.prompt {
max-width: 400px;
margin: 50px auto;
padding: 25px;
background: #fff;
border: 1px solid #e6e6e6;
border-radius: 8px;
}

button {
display: block;
padding: 10px;
width: 100%;
border-radius: 3px;
background: #d83f45;
font-size: 14px;
font-weight: 700;
color: white;
cursor: pointer;
}

JavaScript Servers - Module 3 Page 73


[Link] {
box-sizing: border-box;
display: block;
padding: 10px;
width: 100%;
border-radius: 3px;
background: #000;
font-size: 14px;
font-weight: 700;
text-align: center;
text-decoration: none;
color: white;
}

[Link] {
background: #4787ed;
}

button:hover {
background-color: #c83f45;
}

h1 {
margin: 0 0 20px 0;
padding: 0 0 5px 0;
font-size: 24px;
font-weight: 500;
}

h3 {
margin-top: 0;
font-size: 24px;
font-weight: 300;
text-align: center;
color: #b83f45;
}

form section {
margin: 0 0 20px 0;

JavaScript Servers - Module 3 Page 74


position: relative; /* for password toggle positioning */
}

label {
display: block;
margin: 0 0 3px 0;
font-size: 14px;
font-weight: 500;
}

input {
box-sizing: border-box;
width: 100%;
padding: 10px;
font-size: 14px;
border: 1px solid #d9d9d9;
border-radius: 5px;
}

input[type=email]:not(:focus):invalid,
input[type=password]:not(:focus):invalid {
color: red;
outline-color: red;
}

hr {
border-top: 1px solid #d9d9d9;
border-bottom: none;
}

[Link] {
text-align: center;
font-weight: 400;
}

/* background image by Cole Bemis <[Link]


*/
.messages p {
font-size: 14px;

JavaScript Servers - Module 3 Page 75


font-weight: 400;
line-height: 1.3;
color: #d83f45;
padding-left: 20px;
background-image: url("data:image/svg+xml,%3Csvg
xmlns='[Link] width='16' height='16'
viewBox='0 0 24 24' fill='none' stroke='%23d83f45' stroke-
width='2' stroke-linecap='round' stroke-linejoin='round'
class='feather feather-alert-circle'%3E%3Ccircle cx='12'
cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='8' x2='12'
y2='12'%3E%3C/line%3E%3Cline x1='12' y1='16' x2='12.01'
y2='16'%3E%3C/line%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: center left;
}

Let’s add (as in previous sections) a ‘[Link]’ file to the login folder as well:
[Link]:
section {
padding-top: 50px;
}

Let’s create a login partial view ‘[Link]’ inside the “/views/partials’ folder:
<section class="login" id="login">
<div class="p-5 text-center">
<h1>Sign in</h1>
<form action="/login/password" method="post">
<div class="row">
<label for="username">Username</label>
<input id="username" name="username"
type="text" autocomplete="username" required autofocus>
</div>
<div class="row">
<label for="current-
password">Password</label>
<input id="current-password" name="password"

JavaScript Servers - Module 3 Page 76


type="password" autocomplete="current-password" required>
</div>
<div class="row">
<button type="submit">Sign in</button>
</div>
</form>
</div>
</section>

This file is similar to the one used in the mentioned PassportJS lesson. We create a
form here with the username and password required. After submitting the form, we
send a POST request to the ‘/login/password’ path.
The only difference is that now we are using Bootstrap rows instead of sections
because they better fit our application style.
Let’s change the ‘[Link]’ file. Instead of changing section styles, we want to
change row styles:
Before:
/* ... */
form section {
margin: 0 0 20px 0;
position: relative; /* for password toggle positioning */
}
/* ... */

After:
/* ... */
form .row {
margin: 0 0 20px 0;
position: relative; /* for password toggle positioning */
}
/* ... */

Now we need to create a login view in ‘/views folder’ and link this partial, as well as
new stylesheets, in there:

JavaScript Servers - Module 3 Page 77


<!DOCTYPE html>
<html lang="en">
<head>
<title>Portfolio</title>
<link rel="stylesheet" href="../font/bootstrap-
[Link]">
<link rel="stylesheet"
href="../css/[Link]"/>
<link href="../css/login/[Link]" rel="stylesheet">
<link href="../css/login/[Link]"
rel="stylesheet">
</head>
<body class="position-relative" data-bs-spy="scroll">
<%- include('./partials/[Link]') %>
<div data-spy="scroll" data-target="#navbar" data-
offset="0">
<%- include('./partials/[Link]') %>
</div>
<%- include('./partials/[Link]') %>
</body>
</html>

Our user interface is now ready!


Create a new router for it.
Create ‘[Link]’ file in the router folder:
[Link]
var express = require('express');
var router = [Link]();

[Link]('/', function(req, res, next) {


[Link]('login');
});

[Link] = router

And link it in the ‘[Link]’ as usual:

JavaScript Servers - Module 3 Page 78


/* ... */
var loginRouter = require('./routes/login');
/* ... */
[Link]('/login', loginRouter);

Finally, we should update our navbar by adding a new ‘Sign in’ nav item in the file
‘[Link]’ in the ‘/views/partials’ folder:
<li class="nav-item">
<a class="nav-link" href="/login">Sign
in</a>
</li>

Now we can run the application and see the new tab:

Our user interface is ready and we will use it in the next chapter.

Log in to application
In this lesson, we’ll enable users only to log in, not to create their own account
(we’ve already learnt that, so it’s not the primary goal of this lesson).
Let’s create the ‘[Link]’ file in the ‘/data’ folder and add a sample user.
[Link]:
[
{
"username": "admin",

JavaScript Servers - Module 3 Page 79


"password": "C@keMa$ter"
}
]

Now let’s install the PassportJS with the command:


npm install passport

and its local strategy:


npm install passport-local

Passport local strategy uses a username and password to provide users with local
authentication. We’ll use it to authenticate users in this lesson.
Let’s modify our ‘[Link]’ router file. First, include new packages, as well as the file
system package:
const fs = require("fs")
const path = require("path")
var passport = require('passport')
var LocalStrategy = require('passport-local');

Now use the strategy to verify the following:


 whether the user exists in the ‘[Link]’ file;
 whether their password is correct.

[Link](new LocalStrategy(function verify(username,


password, cb) {
let usersArray =
[Link]([Link]([Link](__dirname,
"../data/[Link]")));
let filteredArray = [Link](x => [Link] =
username);
if ([Link] > 0) {
let usersData = filteredArray[0];
if ([Link] == password) {

JavaScript Servers - Module 3 Page 80


return cb(null, usersData);
}
}
else {
return cb(null, false);
}
}));

We use the LocalStrategy in an analogous way as in the previous module. The only
differences are that instead of using a database, we use the ‘[Link]’ file and
don’t use password encryption.

Encryption is recommended, but it is not necessary in our case. Our current focus
is having authentication working instead of making it secure.
Let’s add the handler to the POST request to ‘/login/password’ endpoint, which is
run by the form:
[Link]('/password', [Link]('local', {
successReturnToOrRedirect: '/',
failureRedirect: '/login'
}));

We want the user to go to the main page after login (we specify that by setting the
failureRedirect parameter) and to go back to the login page if their login attempt
failed (we specify that by setting the successReturnToOrRedirect parameter).
PassportJS authentication needs sessions to keep users logged in. Let’s start by
installing the necessary packages:
 ‘express-session’ to create session;
 ‘express-session-json’ to store it.

We can do this with commands:


npm install express-session
npm install express-session-json

Let’s include them in our [Link] file:

JavaScript Servers - Module 3 Page 81


var passport = require('passport')
var session = require('express-session');
var JsonStore = require('express-session-json')(session);

and use them later:


[Link]([Link](__dirname + '/node_modules/bootstrap-
icons'));

[Link](session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: false,
store: new JsonStore()
}));
[Link]([Link]('session'));

Now, let’s go back to the ‘[Link]’ router file and configure Passport to keep user
information in the login session:
[Link](function(user, cb) {
[Link](function() {
cb(null, { id: [Link], username: [Link] });
});
});

[Link](function(user, cb) {
[Link](function() {
return cb(null, user);
});
});

Our entire ‘[Link]’ file should look like this now:


var express = require('express');
var router = [Link]();
const fs = require("fs")
const path = require("path")

JavaScript Servers - Module 3 Page 82


var passport = require('passport')
var LocalStrategy = require('passport-local');

[Link](function(user, cb) {
[Link](function() {
cb(null, { id: [Link], username: [Link] });
});
});

[Link](function(user, cb) {
[Link](function() {
return cb(null, user);
});
});

[Link](new LocalStrategy(function verify(username,


password, cb) {
let usersArray =
[Link]([Link]([Link](__dirname,
"../data/[Link]")));
let filteredArray = [Link](x => [Link] =
username);
if ([Link] > 0) {
let usersData = filteredArray[0];
if ([Link] == password) {
return cb(null, usersData);
}
}
else {
return cb(null, false);
}
}));

[Link]('/password', [Link]('local', {
successReturnToOrRedirect: '/,
failureRedirect: '/login'
}));

[Link]('/', function(req, res, next) {

JavaScript Servers - Module 3 Page 83


[Link]('login');
});

[Link] = router

Let’s check the functionality by modifying our login view. We’ll pass the user object
as the parameter and display a greeting:
[Link]:
[Link]('/', function(req, res, next) {
if(![Link]) {
[Link]('login', {user: null});
}
else {
[Link]('login', {user: [Link]});
}
});

/views/partials/[Link]:
<section class="login" id="login">
<div class="p-5 text-center">
<% if (!user) { %>
<h1>Sign in</h1>
<form action="/login/password" method="post">
<div class="row">
<label for="username">Username</label>
<input id="username" name="username"
type="text" autocomplete="username" required autofocus>
</div>
<div class="row">
<label for="current-
password">Password</label>
<input id="current-password"
name="password" type="password" autocomplete="current-
password" required>
</div>
<div class="row">

JavaScript Servers - Module 3 Page 84


<button type="submit">Sign in</button>
</div>
</form>
<% } %>
<% if (user) { %>
<div class="row">
<p>Hey <%=[Link]%>!</p>
</div>
<% } %>
</div>
</section>

After logging in, we should see the following greeting:

Right now, we can’t test our authentication functionality because we are kept in the
session after logging in. In other words, now we can log in to the application only
once.

One way to go around this is to open the link in incognito mode. We need to add a
logout functionality to fix this properly.
We can easily implement this, by adding a ‘/logout’ handler in ‘[Link]’ router file:
[Link]('/logout', function(req, res, next) {
[Link](function(err) {
if (err) { return next(err); }
[Link]('/login');
});
});

The [Link]() function above ends the current session. Now we need to create
the button to create the request to the [Link] page:

JavaScript Servers - Module 3 Page 85


<% if (user) { %>
<div class="row">
<p>Hey <%=[Link]%>!</p>
<form action="/login/logout" method="post">
<button class="logout" type="submit">Sign
out</button>
</form>
</div>
<% } %>

If we refresh the page, we see that we are now able to log out from the application:

We can test this functionality by logging in and out multiple times.


If everything works correctly, commit changes to the repository as ‘Add login’:

JavaScript Servers - Module 3 Page 86


Requests from user interface
Although the logging in and out functionality is working, it doesn’t change much
from the user’s perspective. The only page different for logged-in users is the login
page.
In the following two chapters, we’ll add the functionality to delete portfolio photos
from the interface, after which we’ll make this functionality available only for logged-
in users.
Note that this will cause Postman requests to secured endpoints not to work as well
(Postman, by default, is not authenticated to the application, and while it’s possible
to set up, it’s not the goal of this lesson).
In this section, we’ll add the functionality to delete images from the user interface,
regardless of whether the user is logged in. We’ll need a JavaScript front-end script
to send the request from the client.
Let’s create the ‘[Link]’ file inside the /public/js folder.
Create the sendDelete() function in that file:
async function sendDelete(url, filename) {
const response = await fetch(url, {
method: 'DELETE',
headers: {
'Content-type': 'application/json'
},
body: [Link]({
name: filename
})
});

const resData = 'resource deleted...';


[Link]()
return resData;
}

First, we send a DELETE request with the fetch() JavaScript built-in method to
handle requests. The fetch() allows us to make asynchronous HTTP requests from
a web browser (our [Link] file is on the front-end so that the browser
will execute it).

JavaScript Servers - Module 3 Page 87


To use it, we need to provide the URL as the first mandatory parameter. In addition,
we can set options in the object as the second optional parameter. In this case, in
options, we specify the method, headers and body of the request.
Then we send the same JSON in the body as we did with Postman. The page is
then refreshed with the [Link]() method to load images again.
A successful DELETE will remove the image, so while reloading the page, we will
load only non-deleted ones.
Let’s link this script inside the ‘/views/[Link]’ and ‘/views/[Link]’ views. Now
let’s create a button inside the ‘/views/partials/[Link]’ file, which uses this new
sendDelete() function:
/views/partials/[Link]:
<section id="portfolio">
<div class="container">
<div class="row">
<div class="col mb-5 text-center">
<h2>Portfolio</h2>
<p>The cakes I already baked for my clients.</p>
</div>
</div>
<div class="row">
<div class="col-xs-12 mx-auto mb-5">
<button class="btn active"
onclick="filterSelection('all')"> Show all</button>
<button class="btn"
onclick="filterSelection('wedding')">Wedding cakes</button>
<button class="btn"
onclick="filterSelection('christmas')"> Christmas
cakes</button>
<button class="btn"
onclick="filterSelection('birthday')"> Birthday
cakes</button>
<button class="btn"
onclick="filterSelection('anniversary')"> Anniversary
cakes</button>
</div>
</div>
<div class="row grid">

JavaScript Servers - Module 3 Page 88


<% [Link](function(cake){ %>
<div class="hide col-lg-4 col-md-6 col-sm-12
<%=[Link]%>">
<div class="text-center">
<img class="mb-3"
src="[Link]
alt="<%=[Link]%>" style="width:100%">
<h4><%=[Link]%></h4>
<p><%=[Link]%></p>
<button class="btn-danger"
onclick="sendDelete('http\:\/\/localhost:3000\/portfolio',
<%=[Link]([Link])%>)"> DELETE</button>
</div>
</div>
<% });%>
</div>
</section>

Pass URL and image name as the parameter.


To test it, we can add a new image first with Postman:

And then remove it with the user interface:


Interface before the DELETE request:

JavaScript Servers - Module 3 Page 89


Interface after the DELETE request:

Adding security to the endpoints


With the added possibility of making requests from the interface, we now want this
only to be available to logged-in users. We’ll use the connect-ensure-login
package. This package makes the endpoint only accessible to logged-in users
(whose session is active).
Let’s install it with the command:
npm install connect-ensure-login

Let’s open the ‘[Link]’ router file and include this package:

JavaScript Servers - Module 3 Page 90


var ensureLogIn = require('connect-ensure-
login').ensureLoggedIn;
var ensureLoggedIn = ensureLogIn();

We need to add the ensureLoggedIn parameter to the request handler:


[Link]('/', jsonParser, ensureLoggedIn, function(req,
res, next) {
/* ... */

Now we can check the result. Add the Google photo again with the POST request
from Postman. Log in to the application and try to delete it.
Before:

After:

JavaScript Servers - Module 3 Page 91


Now add the image with Postman POST request again and log out from the
application. Try to delete the picture again:
Before:

After:

JavaScript Servers - Module 3 Page 92


Calling the DELETE request while not logged in doesn’t change anything now.
We can also try to call it with Postman:

This request shouldn’t affect the portfolio either.


If everything is working as mentioned, commit changes to the repository as ‘Add
endpoint security’:

JavaScript Servers - Module 3 Page 93


What did I learn in this lesson?
This lesson provided the following insights:
 How to implement user authentication without using the database.
 How to create requests from the user interface.
 How to make endpoints available only for logged-in users.

References
[Link]. (n.d.). Documentation. Available at:
[Link] 10 January 2023).
MDN Web Docs. (n.d.). Using the Fetch API. Available at:
[Link]
(Accessed: 10 January 2023).

3.4. Lesson task - Project 4

The task
In this lesson, we added authentication to our application. In this task, you need to
choose any other POST or DELETE request we enabled in the previous chapters
and create the user interface to send this request.
Make this request (and its editing interface) available only to logged-in users.
Task solution: Click here to reveal.

JavaScript Servers - Module 3 Page 94


3.5. Lesson - Self-study

Introduction

This is a self-study lesson which consolidates knowledge of the third module. We’ll
try to improve the contact section of our application with the map. You’ll need to
integrate with the Google Maps JavaScript API.

JavaScript Servers - Module 3 Page 95


Materials

READ

1. Page: Maps JavaScript API by Google Maps Platform.


2. Page: Use API Keys by Google Maps Platform.
3. Page: JavaScript API Overview by Google Maps Platform.
4. Page: Adding a Google Map with a Marker to Your
Website by Google Maps Platform.

3.5. Lesson task - Self-study

The task
In this task, you need to improve the contact section with a map. The map should
have a marker pointing to the location of John’s shop. (You can choose any
location.)
You need to use Google Maps to do this. You will need to authorise the
Google Maps API first. To do that:
1. Create a new project at Google Cloud.
2. Google Maps API is available for free (unless you change that in the
options yourself). You need to authorise yourself with your credit card,
and you can do that on the Billing accounts page.
3. Next, you need to enable Maps Embed API.

You can see a list of all your enabled APIs here.


4. When you no longer need the project and want to delete your data, you
can delete the project at the resource manager.

JavaScript Servers - Module 3 Page 96


You can read details about setting up the project in the first tutorial linked in the
materials section.
Next, you need to generate the API key. To do that, access the credentials page.
Create credentials to get your key to the Google Maps API. Whenever you will
access the API, provide the key in the URL as the parameter, for example:
[Link]
ameters
In this link, you need to replace the YOUR_API_KEY part with your key.
Next, use the API to create a map in the contact section.
Check jsfiddle for an example of how to use the API.
Make sure the map is visible on both the main page and in the contact section.

JavaScript Servers - Module 3 Page 97

You might also like