0% found this document useful (0 votes)
69 views

ADPS Lab Guide Complete

This document provides instructions for building an Angular application that connects to a Node.js/Express backend server and MongoDB database. It covers setting up Angular and creating components, adding forms and validation, implementing services for separation of concerns, building the Node/Express server, connecting to MongoDB, and adding authentication using JSON web tokens.

Uploaded by

nzfpbte564
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)
69 views

ADPS Lab Guide Complete

This document provides instructions for building an Angular application that connects to a Node.js/Express backend server and MongoDB database. It covers setting up Angular and creating components, adding forms and validation, implementing services for separation of concerns, building the Node/Express server, connecting to MongoDB, and adding authentication using JSON web tokens.

Uploaded by

nzfpbte564
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
You are on page 1/ 277

ADPS7311 LAB GUIDE:

PART A
Contents
ADPS7311 LAB GUIDE:............................................................................................................................ 1
PART A .................................................................................................................................................... 1
Installing Angular-CLI and creating your First Angular Project : ............................................................. 6
Installing Angular-CLI using npm and Node-JS .................................................................................. 6
Creating your first Angular Application (project) .............................................................................. 8
Customizing your application with Visual Studio Code: ....................................................................... 14
Exploring the Angular project structure as presented in Visual Studio Code: ............................... 18
Editing your first Angular component. ............................................................................................ 19
Understanding how Angular and Node JS works to serve pages: ........................................................ 23
Understanding Single Page Applications and Angular Components: ............................................. 25
Creating your first component:........................................................................................................ 26
Event listening, User input , Input Validation and White Listening: ..................................................... 33
Creating your form: .......................................................................................................................... 33
Listening to an Event: ....................................................................................................................... 33
Using Two-way binding to set and read values ( listen to event): ................................................. 36
Using Angular Material to enhance your Angular Pages: .............................................................. 42
Outputting Orders : .......................................................................................................................... 47
Displaying Orders in the Expansion Panel: ...................................................................................... 53
Displaying Orders as they are created. ............................................................................................ 55
Creating and displaying posts using Event binding and Type Safety :............................................ 65
Angular Forms and Form Validation: ................................................................................................... 70
Working with forms: ........................................................................................................................ 70
Understand Underlying methods and using HTML validators ........................................................ 72
Set fields as required ........................................................................................................................ 74
Displaying Error Messages: .............................................................................................................. 82
White Listening with Regular Expressions (Regex) ......................................................................... 84
PART B................................................................................................................................................... 87
Separation of Concerns with Services:.................................................................................................. 87
Adding a Service : ............................................................................................................................. 87
Using the service to receive orders in the orders-placed component : ......................................... 91
Using Lifecycle hooks to prevent memory leaks. ............................................................................ 92
Using the service to create orders in the order- create component : ............................................ 95
Making use of the Observable design pattern to update and pass data between components :
.......................................................................................................................................................... 99
Create the observable : .................................................................................................................. 102
Create the Subscriber : ................................................................................................................... 105
Adding Node JS and Express ............................................................................................................... 109
Client and Server side validation for secure applications:............................................................ 109
Understanding RESTapi’s ............................................................................................................... 109
Create the backend folder and server.js file. ................................................................................ 110
Create your first Node-JS server: ................................................................................................... 111
Understanding Middle ware: ......................................................................................................... 114
Adding the Express framework to speed up the development of our Node Server:................... 114
Installing and using nodemon to auto restart our server. ............................................................ 118
Using our Server to fetch or Orders. .............................................................................................. 120
Installing and using SSL (TLS) with our Node JS Express Server................................................... 121
Fetching posts using our Node JS server and the Angular HTTPCLIENT: ...................................... 127
Understanding CORS and using Headers to allow CORS............................................................... 132
GET versus POST and the POST backend request: ........................................................................ 135
Adding Mongo DB to persist our Data ................................................................................................ 141
Registering for Mongo DB and Creating your Cluster ................................................................... 141
Adding Mongoose to our App:....................................................................................................... 148
Building Mongoose Models: .......................................................................................................... 148
Creating an instance of and using our Model ............................................................................... 151
Connecting our App to the Mongo DB: ......................................................................................... 153
Securing the connection to our Cloud instance of MongoDB with SSL (TLS): .............................. 156
Writing orders to Mongo DB:......................................................................................................... 160
Reading Orders From Mongo DB: ................................................................................................. 165
Deleting Orders from Mongo DB: .................................................................................................. 168
Adding Routing to better Navigate our App: ................................................................................ 175
PART C ................................................................................................................................................. 180
Adding Authentication: ....................................................................................................................... 181
Creating the Login Form: ................................................................................................................ 181
Creating a Route for the Login Form: ............................................................................................ 184
Adding the Sign up Functionality: .................................................................................................. 187
Creating the Add new user Back end and hooking it up the Front end: ...................................... 192
Adding Backend Post Request to create users and store them in Mongo DB: ............................ 195
Connecting the Front end to the back end: ................................................................................... 198
Understanding Single Page Application (SPA) Authentication: .................................................... 202
Using JWT to Provide Login Functionality : ................................................................................... 205
Using JWT to Authenticate Users on the Front end: ..................................................................... 209
Using JWT to protect routes for create and Delete Orders : ........................................................ 214
Adding tokens in order to Authenticate Requests:....................................................................... 218
Adding HTML Sanitizers and HTML Entities to protect Against XSS and other attacks: .............. 227
Using the DOM Sanitizer to Sanitize HTML Output ...................................................................... 232
Handling HTML entities: ................................................................................................................. 233
Error Handling ..................................................................................................................................... 237
Displaying Basic Error Messages: ................................................................................................... 237
Formatting and Displaying custom error messages: ..................................................................... 240
Leveraging Libraries to protect our Application ................................................................................. 249
NPM Audit : .................................................................................................................................... 249
Express Brute to Protect from Brute Force Attacks: ..................................................................... 251
Annexures: Full Project Files: .............................................................................................................. 252
Backend\middleware\check-auth.js ............................................................................................. 252
Backend\model\order.js ................................................................................................................ 252
Backend\model\user.js .................................................................................................................. 253
Backend\routes\order.js ............................................................................................................... 253
Backend\routes\users.js ................................................................................................................ 255
Backend\app.js ............................................................................................................................... 258
Auth\login\ogin.component.ts...................................................................................................... 259
Auth\login\login.component.html ................................................................................................ 260
Auth\singup\singnup.component.html: ....................................................................................... 261
Auth\signup\singup.component.ts ............................................................................................... 262
Auth\auth-data.model.ts ............................................................................................................... 263
Auth\auth.interceptor.ts ............................................................................................................... 263
Auth\auth.service.ts ...................................................................................................................... 264
Error\error.component.ts .............................................................................................................. 265
Error\error.component.html ......................................................................................................... 265
\orders\order-create\order.create.component.ts ....................................................................... 266
\orders\order-create\order.create.component.html .................................................................. 267
\orders\order-placed\order-placed.component.ts ...................................................................... 268
\orders\order-placed\order-placed.component.html ................................................................. 269
\order\order.model.ts: .................................................................................................................. 269
\order\order.service.ts: ................................................................................................................. 270
app.routing.module.ts ................................................................................................................... 272
app.component.css ........................................................................................................................ 272
App.component.html: .................................................................................................................... 273
App.module.ts: ............................................................................................................................... 274
error.interceptor.ts ........................................................................................................................ 275
Server.js .......................................................................................................................................... 276
Installing Angular-CLI and creating your First Angular Project :
https://www.sitepoint.com/mean-stack-angular-2-angular-cli/

Refer to the ADPS GPO Work Around document

Installing Angular-CLI using npm and Node-JS

You will need to use the Node JS Package manager (npm) in order to install Angular CLI to your
machine. (Please note that his might have already been done by your campus IT team). When Node
JS is installed on a machine – the npm tool is installed by default.

1. Open the Node JS command prompt from your start menu:

2. Once the command prompt open enter the following command to download Angular-cli
npm install -g @angular/cli

Let the install complete- you will know that your install was successful if you see the following
output : ( don not worry about the warnings. You want to see that packages were added and a + sign
showing that angular was added. )
Now that you have Angular-CLI installed, you are ready to create your first angular project. Take
note of the following before you start:

You will need to navigate to or create the folder where you would like to create your angular
application – be careful here because you can only launch your application to the browser from
within this folder.

Node JS makes use of normal Windows Command Prompt (CMD) commands such as:

cd – to change a directory

mdir – to create a folder etc.

Creating your first Angular Application (project)

1. Create / Navigate to the folder in which you would like to store your project. I am storing my
project in my documents in a folder named ADPS.

2. Issue the following command ( Only if you are in the desired folder)

ng new your-project-name
3. Accept the default settings when prompted ( You can just press ENTER for each question).
The settings we would like are:
a. Select NO for routing
b. Select CSS as the style sheet.
4. You will see the following output while your application is being created:

5. You will know that your application was successfully created if you see that packages were
added ( look on the last line)
6. You should also be able to see the application folder if you list the files inside the ADPS
directory by running the dir command:

7. You can now test your application by navigating into your project folder and by running the
following command:

ng serve
8. You should see output indicating that your application compiled successfully. You will also
see that the server is listening on localhost:4200. This means that you are effectively running
a webserver on your machine , you access this webserver by entering its name : localhost
and the port on which the server is listening : 4200 into your web browser
9. Hit the Enter key once you have entered the URL . You should see your Angular Application
launched in your browser:

We are now ready to start customizing and securing our application. We will need to use an IDE in
order to do so. Visual Studio Code is a light weight , free and powerful IDE often used with angular.
The next section will take you through the necessary steps in order to open and start customising in
VS Code.
Customizing your application with Visual Studio Code:

We are now going to launch Visual Studio Code and familiarise ourselves with both the IDE and the
structure of an angular application. We will start editing the application so that you can see how
angular works and then delve a bit deeper into what angular components are and how they work.
Go ahead and follow the steps listed below:

1. Launch Visual Studio Code from your start menu:

2. You can click File and then Open Folder in order to access your application through Visual
Studio code:
3. Navigate to your folder and click on Select Folder to open your application in VS Code:
4. You should see your application displayed similarly to the following:

5. We are going to add two extensions to assist us with our application. The first extension will
allow us to import ready to use icons to use in our application. The second extension is
called angular essentials and optimises VS Code for angular applications.

6. Click on the extensions Icon:

7. Search for Angular Essentials and click install ( Click on the green install icon – mine is not
showing because I already have angular essentials installed) :
8. Follow the same steps to install The Material Icon Theme extension.

Now that we have our extensions installed – let us take a look at the folder structure used by angular
applications.
Exploring the Angular project structure as presented in Visual Studio Code:

Make sure that your application is running in your web browser before you start this section. If you
are not sure – Click on the terminal in Visual Studio – you should have the following output: (If you do
not simple enter the ng serve command into the terminal)

Now that we are sure that our application is running, lets take a look at the folder structure so that
we know where to find the files we will need to code in.
The scr folder contains the Angular
application. We are going to use this folder to
create our Angular components ( Next
section) and to create our UI. This folder has
many sub folders that we will explore and use
as we go along.

Package.json – lists all packages installed with


the npm command - you will see the angular-
cli module that we installed if you open the
folder. The module itself is stored in the
node_modules folder

Editing your first Angular component.

1. Go ahead and expand the src folder – you will see the following sub folders.

We use the app folder to create our


components and in turn our UI, If
you open this folder you will see
quite a few app.component files .
2. Now extend the app folder to see the app.component files:

You should be able to recognize the css and html extensions as web development files – we will
explore how these files work within an Angular application next.
3. Open the app.conponent.html file – You will see that this is the html file is the file that is
currently being read and displayed by your browser (This is not the actual file displayed – but
more on that a bit later) :
4. Let’s go ahead and edit this file, change the app.component.html file by changing the <h1>
header tag to read My First Angular App – or to anything you prefer.

5. Add an <h2> tag that reads : File has been edited.

6. You should be able to see the changes on the web page in your browser( remember to save)
Understanding how Angular and Node JS works to serve pages:

It is important to remember that Node JS is currently providing the web server capabilities that we
need. Web servers serve web pages to client machines that request them. Typically loads of
websites are hosted on a web server in folders for example, one web server could have folders
called : salesworld.com , sydneyAquirim.au etc. Inside each of these folders is a landing page
labelled index.html. The web server knows that the filed saved as index.html is the first webpage it
should display in the browser if a client machine requests a website by entering the
www.sydneyAquirim.au url.

Angular works the same – Node JS will display the index. html page. (This page is shown in the image
below:)

This might seem very confusing at first – we just edited the app.component. html file and that made
changes to the file in the browser – furthermore , none of the html tags seen in the
app.component.html is present in this file – how does this work then?

As we have mentioned before, Angular makes use of components. These components are then
injected into the index.html page as script tag <scritp> which runs the JavaScript needed to render
and display our UI. We can see this if we look at the source code of the page displayed in the
browser:

If we right click on the page currently displayed in the browser and select view page source we will
see the following:
Do you see the injected script tags just under the <app-root> tag ? If you look back at the index. html
page you will see that the only html tag (element) contained within the <body> tags is the <ap- root
> tag. The app root is a custom component used to create our UI – you can open the
appcomponent.ts file and look at what this component contains:

As you can see this file contains the app-root component that will inject the contents of the
app.component.html file and the app.component.css file into the index.html file as JavaScript tags
(<script>). This injection is why the changes we made to the app. component.html file is displayed
through the index. html file. In the next section we take a better look of how Angular components
work.

Understanding Single Page Applications and Angular Components:

<app-
<app-header> search>
<app-nav>

<app-detail

<app-footer>

<app-callme> <app-chat>

Single page applications act much the same as mobile apps. You never click a link to move to another
page – the web updated is refreshed with the information you need once you click on a different
link. Different parts of the web page can also be updated at different times. This is possible because
of components. Instead of coding all the logic into a single web page , we create components that
react to user input etc independently. You usually create components for features of your page that
is decoupled ( the search feature has no baring on the live chat feature) and contains sufficient log.
These components are also re-usable. In order to understand how these components work, we are
going to create our own component now.
Creating your first component:

1. It is good practice to create your components in sub folders – in order to create a new sub
folder in the app folder, right click on the app folder and select new folder from the shortcut
menu. Call this folder orders:

2. Follow the same steps listed below to create a further sub file inside the orders file named
order-create. This folder structure helps us contain each component and all its files in one
folder.

3. We now need to start creating our order-create component files. We do this by creating the
following two files (right click, new file) in the order-create folder:
a. order-create.component.ts ( This is the type script file that will contain our logic)
b. order-create.html(this will contain the HTML coding for our UI). You could also
create a oder-create.css file for styling.
We use the .ts extension for order-create
component.ts file because we are using
TypeScript. TypScript is a superset of JavaScript
used to code large scale applications. (super set
means the language has been enhanced and
refined to scale better to larger applications)
4. Now that we have the two basic files
created , we can go ahead and create our first component. Open up the order-
create.component.ts file. You should see the following empty file:

5. We first need to create a TypeScript class – please note that we will never need to instantiate
this class to create objects – Angular will take care of that part of the process for us. We are
simply explaining what we want each created order to look like.

6. One we have created the class, we next need to convert our class into a component. We do
this by importing the Component decorator from the Angular-CLI module we installed. You
need to add the lines of code indicated below to your order-create-component.ts file.
Imports Component library from
the angular-cli model we
installed in the beginning of the
guide

Component: Used to mark TS


(Type Script) file as a
component

Selector: Allows us to select /


call a component to be
rendered and displayed in the
Remember that Node JS and Angular creates a server – side HTML files.
scripting language. This means that the processing of the actual
code is done by Node JS and presented to the user in an HTML file.
You will see no Java Script in that file. Only HTML output. We code
all the logic into the component which we select to be displayed by Template URL : Points to the file
the Main HTML page using the selector. We then format the output position of the HTML file that
using the TemplateURL file.. will be used to format the
output of our module

7. Lets create some output in the HTML file and then actually go ahead and select the
component and display it. Open the order-create-component.html file and add the
following code:

8. We next need to instruct angular to call the component and then to inject the java script
into our HTML file. We do this by registering a component in a module : Open the
app.module.ts file:
9. We need to import the OrderCreateComponent file to show angular where to find the code
that we would like to inject. To do this, we add the following line of code:

We tell angular what we want We need to tell Angular exactly


to import in order to inject the where the information is stored by
code in that file into the HTML providing the relative file path.

10. We next need to add the component that we have just imported to the declarations array
(This array holds all the components that needs to be called and injected when the website is
launched) Edit the array as follows:

11. Your completed file should look like the following image:
12. Lastly, we need to add our component to an HTML file to be injected into: Open the
app.component.html file:

13. You can now add your component as a custom html tag: Edit the app.component.html file as
follows:

14. Save all your changes and restart the NodeJS server by running ng serve:
15. You should be seeing the following output:

16. You now have two components which function completely independently in a single page
application (SPA). If you view the source code of the page you will see the following:

Our component being called


as a custom HTML tag

The actual Java scripts being


injected into the HTML file.

17. We are now ready to create our order-create component. Remember that this is an
application development security course – we will thus need to make sure we secure the
textboxes with white listening using Regex and input validation to ensure we have no empty
fields. We do this in the next section.
Event listening, User input , Input Validation and White Listening:

Creating your form:

We are now ready to start interacting with our users. We need to set up a form to enable users to
log on or register on our platform. We need to make sure that we set this up using secure coding
methods. We will start with the very basics : Form Validation. Form validation includes the
following:

• Ensuring that no empty fields are passed to our database


• Ensuring that all data entered is in a valid format
• White listening and preventing dangerous characters which could leave us vulnerable to XSS,
Directory traversal and any type of injection attack.

Let’s create this form now.

**Please note that the <br> tags are not good coding practice and was only added here in order to
better display the form. We will change over to formatting with Google’s Material later in this
section**.

Listening to an Event:

1. We now need to give the browser the logic we want to execute once a user clicks on our
button. We do this through event binding. Event binding is an angular feature that allows us
to listen to events that we declare. In order to do this we edit our button as follows :

Angular Event
binding that listens Method to be called from our order-create
to a mouse click component class once the button is clicked
2. We now need to go and create the method that we are calling form our component class.
Open the order-create-component.ts file and edit it as follows:

We will just pop up a small


alert message for now

3. Save all your changes and you should see the alert message pop up when you click on your
button.
4. We are now able to listen to events - we next need to get the input from the user and
output it to the screen. We are going to start by outputting a dummy value: Edit your order-
create-component.ts file according to the following:

Setting the newOrder


property

Setting the value of the


property in order to
output it

5. We will now use String interpolation to output the dummy value in our HTML file. Edit your
HTML file according to the following: ( you can read more about String interpolation here:
https://angular.io/guide/template-syntax)
6. Save your changes and click on the Order Now button on your page – they dummy value
should appear underneath the button:

7. Now that we are able to output dummy data – lets move to retrieving what the user enters
into the textbox and displaying it on the screen. We will be using Two-way binding to
achieve this. Two-way binding combines the setting and reading of values.

Using Two-way binding to set and read values ( listen to event):

1. We will be using the ngModel directive in order to both set and read the value entered by
the user in one smooth step. ngModel is not imported into angular by default, thus we will
need to import it first.

ngModel is an angular directive that acts as an instruction to an HTML element in the DOM. It
basically allows you to use Java Script (TypeScript in our case) to instruct an element on what to do
when it is accessed. We are going to use this directive to instruct a button to save and output (Two
way binding) what ever the user types in a textbox.

2. Open your app.module.ts file and edit it accordingly:


Add the import form the Angular Make sure you add this to the
FormsModule portion of the imports array so that Angular
Angulare/core Framework. This can be aware of and use the
will allow TypeScript to find the import.
import
3. Now that we have our imports ready, we can start editing our order-create.component.ts
and order-create.component.html file. We will start with the order-create.component.html
file.
4. Add the [(ngModel)] directive to your username textbox. You also need to bind the ngModel
to an attribute you do this by entering [(ngModel)]= “userName”

**Don’t worry if the userName property is underlined with a red squiggly line – it is because we have
not defined the property in our order-create-component, we will do so next.

5. Next we need to define the property in the order-create-component.ts file. Open this file
and edit it according to the following:
5.1. Create the UserName property
5.2. Write the value that user enters as a user name to the new order Property.

[Grab your reader’s attention with a


great
5.1 quote from the document or
use this space to emphasize a key
point.
5.2 To place this text box
anywhere on the page, just drag it.]
6. If we update our webpage, we should be able to enter the user name and then display it
where we currently have the “Order is placed text”:
You can read more on both the ngModel and the DOM by using the links below:

ngModel:

https://angular.io/api/forms/NgModel

https://www.w3schools.com/angular/angular_model.asp

https://angular.io/guide/user-input

DOM:

https://www.w3schools.com/whatis/whatis_htmldom.asp

https://www.computerhope.com/jargon/d/dom.htm
https://www.youtube.com/watch?v=H63dVFDuJDM

Using Angular Material to enhance your Angular Pages:


Angular material is predefined design components that you can use in your website. It allows you to
quickly and easily style your page with minimal coding. You can read more about it here:

https://material.angular.io/

We will need to install the material framework using the ng add @angular/material command in the
terminal.

Answer yes to all the options that you will be asked during the installation process.

You will the below screen if your installation was successful.

We can now use the google material attributes to style our webpage. We will need to import each
module in order to use them. In order to do this, open your app.module.ts file and edit it as follows.
Add the following modules to the Make sure to import the modules
imports Array: from the @angular material
framework
MatInputModule : To style your
input boxes

MatCardModule: To style your


forms

MatButtonModule: To style your


buttons
We use these modules in our order-create-
component.html and new order-create-component.css file. Lets edit the orer-create-
component.html file first.
1. Edit your original User Name input field as follows:

The <mat-form-field> element The matInput Directive is used in


informs angular that the HTML order to allow the elements to work
element needs to be styled with with Angular Material.
Angular Material .

2. Go ahead and edit your entire form:

3. Save your changes – your web page should look as follows:


4. We are also going to add a card view to this web page : Edit your html page as follows:

The <mat-card> tag allows you to show


sections of your page in a card view.
There are many different ways in which
you can use this tag – you can read more
about it here:
https://material.angular.io/components/
card/overview

We have wrapped our entire form and


button with the <mat-card> tag.

3. We are also able to style our card view using css. In order to use css files with our component
we need to create create-order-component.css file in the create order folder as follows:
4. We next need to register the css file in our order-create-component.ts file in order to notify
the component that it needs to look for the .css file to style our web page. After you have
created the file you can register it by editing your order-create-component.ts file as follows:

Add the styleUrls array and add the


relative path to your order-create-
compononent.css file.

**This is an array because we can


add more than one style sheet.

5. Now that we have registered our style sheet, we can go ahead and add some styling to our
card view. Edit the order-create-component.ts file as follows:

We are editing the width


attribute to make sure that
the card- view only uses 50%
of the screen’s width and we
are using the margin : auto
attribute to automatically
crate a border that matches
the width
6. If you save all your changes and relook at your website, it will look much different than
before:

Outputting Orders :
1. Before we go ahead and secure our form with some form validation and white listening, we
need to output the orders as they are placed. In order to do this, we will create the order-
placed sub folder in the orders folder and add the three necessary files to create , output
and style this component :
• order-placed.component.css
• order-placed.component.ts
• order-placed.component.html

2. Lets edit the TS (Type Script) file first:

** Remember that this is the Java Script framework that we are using to supply the code behind our
forms.

3. Open the order-placed-component.ts file and edit it as follows:


`

Create your TS class – as before, we Add your component decorator and


will use this class to add all the logic add the :
to our web app.
• Selector to point
• templateUrl
• StuleUrl

Adding the @Component decorator


should automatically add the
necessary import

4. Next we need to register the component in the app-module file. Open the app.module.ts file
and edit it as follows:
Add the OrderPlacedComponent Import the OrderPlacedComponent
class to the NgModule declarations class
array.

5. We can now use the custom html tag that represents our component ( which is made up of
the .ts , .html , .css files) in the app.component.html file. Add the tag /element as follows:
6. We can test if the component is working by adding a single line to the order-
placed.component.css file:

7. We should be able to see the output when we save our changes:


8. Let’s start by displaying some dummy Orders. We will first need to code up the HTML for
this. In order to do this open the order-placed.component.html file. We will be adding the
Expansion Panel as well as an accordion wrapper, this will allow us to expand and contract
our orders. We need to import these two features from the angular material framework.
Edit the app.module.ts file as follows:

9. Now we can use the Expansion Panel in our HTML edit your order-placed.component.html
file as follows:

10. If we now render our HTML we should be able to see and expand our expansion panel.
Displaying Orders in the Expansion Panel:
We are now ready to display some dummy Orders.

1. Open your order-placed.component.ts file and add the following dummy values in an array:
** This array will contain properties for userName and Order Details. You create these
properties by giving the name for the property followed by a : (colon) and then the value of
the property in single quotes ‘’ e.g: userName:’User1’

2. We now need to loop through these values and display them in our HTML file. We will make
use structural directives for this. Structural directives (remember a directive tells an
JavaScript Script what to do with an element.) allow us to structurally alter the HTML output.
We will be making user of :
• *ng-For which functions like a for each loop
• *ng-IF which functions like an if function.

3. In order to loop through the dummy values in our array, let’s edit the order-
placed.component.html file as follows:

The NgFor directive works


as follows:

Let post : creates a


temporary variable called
post.

Of posts: Tells ngFor to


loop over the size of the
posts array

We can then access the value stored in the post temporary


variable with each iteration using string interpolation.( see
earlier)
4. Our display is still not visually appealing. You will notice that the expansion panel fills the
entire screen and our mat-card only fills 60%. In order to correct this we need to do the
following:
5. Open the order-create.component.css file and delete out your entry for mat-card {}.
6. Open the app.module.html file and add the main element to wrap your custom elements
(components)

7. Now open the app.component.css file and add the following:

8. If we now save our changes and look at our webpage, we will see that all the components
are correctly styled AND our dummy data should display:
9. We should also be able to expand our dummy items:

It is now time to display these fields with the actual data entered by our users:

Displaying Orders as they are created.


1. We first need to tell angular what to do if no posts are displayed – in order to do this we will
make use of Ng-if. Open the order-placed.component.ts file and delete out all the values
stored in the array:
If you save your changes and relook at your website, you will see that nothing is displayed:

2. We can edit our order-placed.component.html file to use *Ng-if to check if the array if
empty, and if the array is empty it can out put “ no orders placed yet” as a value. In order to
do this, edit your file as follows:

We use *ngIf to check if the post arrays contains any values – if it does we use *ngFor to loop
through them and display them.

If it does not – we output no orders created.


3. If you save your changes – your webpage should display as follows:

4. We will start by working on the order-create.component.ts file. We first need to create


variables that we will use with Two way binding in order to store what the users enters into
an array of properties. Create the following variables:

5. Now we need to use two way binding in order to get the value that the user types into the
input fields and then store it in the variables we created in the order-create.component.ts
file. We will edit our order-create.component. html file in order to do so. Open this file and
edit it as follows:
We are using ngModel to instruct Angular to get the value the user enters into the
input field and to bind it to our variables from the order-create.component.ts file.
Next we will store those variables into an array of properties.

6. Now that we have access to the variables, we need to save these variables into our array of
properties. Go back to the order-create.component.ts file and edit it as follows:

We create a constant called order. For example – we store the value


We then store a Java object with the that the user provided in the
following properties in the constant. enteredUserName variable to the
We assign the values the user userName property .
entered to each of the properties.
7. We now want pass this data on to the order-placed.component.ts file in order to display the
posts as the user’s enter them. This is done by emitting an event. You can read more about
emitting events from here: https://dzone.com/articles/understanding-output-and-
eventemitter-in-angular

8. In order to emit an event, we need to call in an angular feature that will enable us to emit
our event. Add the import for the EventEmitter feature as shown below:

9. Now we are ready to emit our desired event. We need to create an EventEmitter object –
we do this as follows.

10. We can then tell Angular to emit our constant that we created earlier. We do this as follows:

We are telling Angular that we would


like to make our order object available
to other files within our webpage, we
thus would like to use the
orderCreated emitter to emit our
order object.

11. Lastly we need to tell angular that orderCreated is an event that it should listen out for (
think back to event handling in PROG6211 and PROG6212). In order to do this we are going
to wrap orderCreated in a decorator. We have already imported the OutPut decorator, we
will now just use it as follows:

We are using this decorator to inform android that orderCreated is an event


that we would like to use to Output the value of our order object to other
files (listeners)- this is actually from the parent component where we call the
<app-order-create> selector from( the app-component), but you will see this
as we go.
12. We now need to get each post that the user enters from the order-create.component.ts file and
store it in a list or array of posts in the app.component.ts file. We are using the app.component file
because only the parent component is able to listen to events that we emit from the child
components. Our structure is currently as follows:

app.component
made up of the .ts , .css
and .html files

order-create.component order-placed.component
made up of the .ts , .css made up of the .ts , .css
and .html files and .html files

This means that the app.component can listen to events being emitted from the order-
create.component and then pass the data from that event to the order-placed component to display
the data.

12. Open the app.component.ts file and edit it as follows:

Remove the title Created an empty Now create a method onOrderCreated that will accept
entry that is Array called an object order as a parameter. We then fill the array
currently there storedOrders with each order as the user clicks the order button
13. This means we are currently filling an object called orders with the input we get from our
user. We then use the Emitter and the Ouput decorator to pass this data to the
app.component which will accept the data as an argument and push it into an array. We will
then pass this array to the order-placed component to iterate over and display.

14. We now need to edit the order-placed.component. ts file according to the following.

We start by importing the Input decorator – we use this decorator to accept the data
from the storedOrders array in the app.component.ts file and store it in the empty
orders array.

15. We are no ready to glue all of this together – as mentioned before, we need to do this in the
parent component. We need to pass the data through the html pages. We will edit our
app.component.html file according to the following:
So lets walk through the logic of what we have set up here:

1. We created our own event that angular can listen to using the EventEmitter (we created this
in the order-create.component.ts file. This allowed us to listen to every post the user
entered and store it as a Java object.
2. We then used the app.component.ts file to listen out for the event. Each time the event is
fired the object is pushed into an array using the onOrderCreated method.
3. We then pass that array to the orders array in order-placed.component.ts file and loop
through this in the order-placed.component.html file.
4. If we save our changes we should be able to see the post we make:
Creating and displaying posts using Event binding and Type Safety :
We firstly need to make sure that all our orders look the same. In PROG6212 you learned to assign a
class as a data type – you created lists of type Person for example. This “Type Person” was actually a
class or interface that contained properties that defined what the elements of your list needed to
look like. We are going to create an interface that will instruct angular of what an order should look
like. Interfaces like these are referred to as model – you now have a full MVC application:

Model : The interface that depicts what our Posts should look like ( which will speak to our DB)

Controller : is our Type Script component file that holds our application logic.

View: Our CSS and HTML files that renders our output that the user sees.

Lets go ahead and create our model.

1. Create a new file in your orders folder and call it order.model.ts:


2. Create an interface that we will use to create our own “data type” to force our orders to
look a certain way – this is known as Type- Safety:

3. We will use this Type to create and display Orders. We need to import the interface into our
order-create-component.ts and order-placed-component.ts files. This will enable us to use
the component as a Type for our orders in these files.

4. Lets go have a look at how we would store some of our created orders using the Order type
in the app.component.ts file. First import this file as follows:

5. We want our website to accept and then display as many orders as users decided to enter.
For now ( we will use a MONGO Database later) we need to store each entered order in an
array of type Order. We can edit our app.component.ts file further as follows:
The above syntax sets the storedOrders array to the type of Order – it will thus only accept
properties from our Order interface in our Array( userName, Email and PlacedOrder – we
can now not store incorrect values – this is known as Type-Safety. Angular will throw an
error if we try to save anything else in our array. This model will also help us to connect to
the database later. Type safety is small often overlooked security feature

6. We next to import the Orders interface into both our components. We will edit the order-
placed.component.ts file next:
** Don’t be too concerned if you see the following error – your project will still comply – this
error appears because the array in app.component is empty – Angular is telling you it needs
to contain userName, Email , and PlacedOrder. We need these arrays to be empty.

7. Finally we are going to edit the order-create.component.ts file according the the following:

We set our object’s data type to We also tell our emitter that it will
type Order ( do you notice that we emit data of type Order ( You might
don’t have a red squiggly line here ? recognize the <Order> data type in
That is because the object contains <> these characters from both
all the properties we demand in the OPSC7311 and PROG6211
interface)
We are now ready to move onto our next section. We now have a functioning web app that we need
to further secure ( further than Type-Safety). We will optimise this program to make better use of
forms and all the built in functionality this gives as well as secure our form in the following ways:

• Setting fields as required


• Using ng-pattern to assign a regex pattern that data needs to be checked against.
• Setting data fields as valid and invalid
• Protecting our form from any type of injection attack by using htmlentities and
htmlsanitizers:
Angular Forms and Form Validation:

Working with forms:


We are now going to edit our application to make full use of all the built in features we get from
using forms. We are going to edit the order-create.component.html file according to the following:
2

1. We will now use a full html form – this means that we need to move our button into
the <form> element and set it to type submit. The default HTML 5 form behaviour is for
a button to submit all the values of a form. You can read more on this here :
https://www.w3schools.com/angular/angular_forms.asp &
https://www.w3schools.com/html/html_forms.asp

2. You will also notice that we are no longer calling the onAddOrder() method on button
click – we can use the (submit) event in the form header to instruct Angular to process
the form when the user clicks submit. This means that Angular must run the
onAddOrder() method

3. When angular detects that we would like to submit a form, it automatically creates a Java
object that will contain controls which will store the value of each of our input fields. We
can later access and use these controls. The #postOrder local reference allows us to
access the values in this object. We then assign the ngForm directive as a valueto the
#postOrder local reference. ngForm is the Angular directive that actually creates the
object.
You can read more about ngForm here : https://angular.io/api/forms/NgForm
We finally pass the postOrder reference containing the values we need to the
onOrderAdded(postOrder) method as an argument.
4. We are no longer using two way binding, so we can replace the [(ngModle)]=
“enteredValue” binding and replace it with the directive ngModel. ngModle will allow us to
access the values of the entered fields by the name attribute. :

6. We can now move on edit the order-create.component.ts file to accept our values as
follows:

1. In order to use all the form features we need, we need to import the NgForms module
from the @Android/forms framework.
2. We next need to tell onAddOrder that it is accepting a Java Object named Orderform
from NgForm.
3. We can now use this objects value of feature to get access to the values in our object.
4. ** I would recommend that you save all your changes and double check your application
at this stage. You should notice that all the previous errors caused by empty arrays are
now gone:)
Now that we have a fully functioning form – it is time to validate and secure this form.

Understand Underlying methods and using HTML validators


ngForm gives us access to several built in classes that we can use to validate the input that users
provide to our forms. As developers it is crucial that we make sure that we have valid input. In
Information security we speak about the information security triad : CIA AAA this stands for:

Confidentiality: Data should only be available to whom it was intended for.

Integrity: Data should remain unaltered.

Accessibility: Data should be available 99.999% of the time (the rule of 9’s)

Authorization: Only people who are authorized should be able to view our data.

Authentication: We need to make sure that users say who they say they are.

Auditing: We need to keep track of who has accessed the data – valid or invalid requests.

User input is where we start with this. Unvalidated user input will affect every element of CIA AAA.
In your textbook you would have learned about white listing and validation. We are now going to
secure our form by :

• Setting our fields that are required as required.


• Making sure our data is accepted in the correct format
• Use ng-pattern to implement a regex pattern to make sure that we accept on dangerous
input that could make our website vulnerable to cross-site scripting (xss) , any type of
injection attacks (sql injection) Directory traversal attacks etc.
• We will not allow the form to be submitted if the above conditions are not met.

Now, back to those classes Angular provides us with. These are:

ng-pristine: The form field has not had any data entered yet

ng-dirty: The form field has had data entered

ng-untouched: The form field has not been clicked on

ng-touched: The form field has been clicked on


ng-valid: The data in the form field is valid

ng-invalid: The data in the form filed is invalid

You can read more about these classes here: https://docs.angularjs.org/guide/forms

If right click within the form of your application and click on the inspect entry from the shortcut
menu – you should be able to see these classes being applied to your form fields.

This screenshot was taken before I clicked on any of the fields – note that ng-untouched and ng-
pristine classes are currently applied to the form-fields. The screenshot below was taken after I
clicked on the field – you should be able to see that ng-untouched has changed to ng-touched.
These classes all make use of a Boolean value that is set to either true or false as we access and work
with our forms. These variables are :

pristine Dirty

Touched Untouched

Valid invalid

We have access to these class and we can tell angular what to do based on these events. We are
going to start by setting our fields as required.

Set fields as required


1. We are going to set our fields as required using the regular HTML validator field required.
Edit your order-create.component.html as follows:
2. If you now save your changes, you will notice the fields are marked with an * and turn red if
we do not enter a value :
3. Further to this, if we inspect the form – we van see that it no longer reads as valid but
invalid: That is because the class variable or property for valid has been set to false.

4. Next we need to access these classes (actually their class variables) and take a look at how
they change when we access the form. Further edit your order-create.component.html file
as follows:
We are using string interpolation {{value }} to output the actual values stored in our
postOrder object / at form level. Each of these variables will output true or false: Lets
render this page and have a look at what this looks like.

If we look at the above image you can see that the username is not touched – that is why
touched is false and untouched is true. No text has been entered , that is why pristine is
true and dirty is false. This is a required field and we have not entered a value, that is why
valid is false and invalid is true. If I now type a value it will change as follows:
Now we have typed in a value touched is true and untouched is false. There is text in the
field so pristine is now false and dirty is true, however valid should now be true and invalid
false. We will see this when I enter values for all the fields (remember we did this at form
level and set ALL our fields as required)

The following YouTube video might be helpful: https://www.youtube.com/watch?v=d8XONHXTv_4


5. Lets set up the remainder of our validators and then use the above properties in order to
secure our form. Edit your create.component.html as follows:

Use the minlength Set a pattern using the Set the maxlength of
property to set the above regex pattern. the or the order field
minimum amount of (More on this later) to to accept no more
characters that the ensure that the email than 50 characters.
userName field will field will only accept a
accept to 8. valid email

6.We can now use these properties to better secure and control our form. For example, we can
decide not to submit a form if invalid is true. In order to do this, we can edit or order-
create.component.ts file as follows:
We can instruct angular to return to main component if the invalid variable is set
to true. This means that no empty forms will be submitted, the form will also not
submit if the userName is less than 10 charactes, or if the email does not match
the email pattern and finally if the orders field contains more than 50 charactes.

User name is 10 or less characters = valid

Email Address is incorrectly formatted


=invalid and marked as invalid

The order field is less than 50 characters =


valid
The purple highlighted form field is The next form field is Order, which
the Email form field – it is marked as does meet our validation
invalid requirements and is marked as vlaid

However we are making sure our entire form is valid before we allow it to be
submitted – our form will thus not submit at the moment.
6. When we fix the e-mail form field, the form is valid and it will submit:

Displaying Error Messages:


1. We now need to display error messages to our user, we need to be careful as to what we
display in these error messages. For example, it is possible to output usernames etc. Keep
your error messages as generic as possible and only provide information the user needs to
correct the incorrect entries.
2. Angular material has a built in <mat-erro> element that works with the *ngIF structural
directive – it will check if a form field is invalid and then display the error message we
choose through string interpolation.
3. We will first create our error messages. Open the order-create.component.ts file and edit it
as follows:
4. Now open the order-create.component.ts file and edit it as follows:

We first create a local reference We next use the <mat- error> element
variable called enteredUsername , we and *ngIF to determine if the value stored
then set it as ngModel. nfForm will give in the local reference variable is invalid –
us access to the entire form and we then output the error message from
ngModel gives us access to the our order-create.component.ts file using
individual elements in a form. string interpolation.

5. Go ahead and apply the changes to all the form fields:


6. If we now save our changes and try to submit and empty form or an incorrectly formatted
form, we will get the following error messages.

There are many other HTML validation attributes that you can use. You will find a list of them and
what they can do here:

https://angular.io/guide/form-validation.

https://www.w3schools.com/js/js_validation.asp

White Listening with Regular Expressions (Regex)


Your textbook would have explained to you that white listening is the process of defining which
characters and input field will allow. We do this with Regex. Regex is the Java implementation of
Regular expressions. These are string patterns that we use in order to define exactly which
characters a textbox will accept. For example – if a user enters this: <script>alert(‘XSS’)</script>
and our web app is not properly set up, the code might be executed. One of the simplist ways of
avoiding cross site scripting (XSS) and SQL injection attacks is white listening with Regex. A regex
pattern looks like this: Global key word (g) will
Range[]: /([A-Z])\w\g search the entire string
this will
match Word \w
Capitals Will match
any word
End of regex containing
Beginning of Capturing
pattern \ capital letters
regex pattern group ()
A-Z
/
A regular expression for email looks like this (there are several different verions):

(image courtesy of : GitHub: Learn Regex)

If you have been paying attention, you would have noticed that we have already assigned a simple
Regex pattern to our e-mail field by using the HTML pattern validator: I took this pattern from the
Regex library that you can access from here: http://regexlib.com/Search.aspx?k=email

You will find that this will allow most simple e-mail addresses. You can find many different patterns
to apply there.

1. We can thus be quite specific about we want to allow into our input fields. We could use the
following pattern for order to accept only Upper case and lower case letters and numbers.

2. We can further set a pattern that allows the same characters as the order input field, but
which also allows an underscore and dash:
3. If we now save our changes and enter values into our form we will notice that we can only
input the characters that we have specified:

4. If we now enter an unlisted character we will get our error:

5. This will go a long way towards not allowing dangerous strings into our input fields.

You can learn more about RegEx from the following sites:

https://github.com/dwyl/learn-regex

https://regexr.com/

https://angular.io/tutorial/toh-pt4

You can also learn more about cross site scripting here.

https://www.softwaretestinghelp.com/cross-site-scripting-xss-attack-test/
PART B

Separation of Concerns with Services:

It is important to remember that good security goes much farther than just protecting your
textboxes and validating your input. You need to design robust software which follows good design
principles. The software should also be easily maintainable. If we relook at the CIA AAA
recommendations, you will remember that Availability and Integrity was amongst them. The best
way to work towards providing high availability is to design robust software. Separation of concerns
is a design principle that allows a developer to design software that each has a singular function.
Should changes to the software be requested in the future , only one part of the program needs to
be amended without compromising the rest of the software. Stack Overflow provides a really good
explanation as to why we should implement separation of concerns:

https://softwareengineering.stackexchange.com/questions/32581/how-do-you-explain-separation-
of-concerns-to-others

Adding a Service :

At the moment our application is passing around and possibly exposing data. We are going to
tighten up the functionality of adding and displaying orders by implementing a service. The Angular
documentation clearly states that components should not pass data around but should focus on
displaying or retrieving data. You can read more about services here :
https://angular.io/tutorial/toh-pt4.

Our service will provide us the service of both adding and displaying orders. Coding in this manner
allows us to make changes in one place. If we are later asked to add a delete or edit order
functionality , we can make the changes to the service and simply update the corresponding
components in the .TS file , instead adding multiple lines of codes across the .html and .Ts files.

Let’ start creating our service:

1. Create a new file in your orders folder and name it order.service.ts


2. A service is nothing more than a class in Angular. Open the order.service.ts file and edit it
according to the following:

1.Dependency Injection (DI) We will be injecting our service into our create-order and placed- order.
component.ts files. This means that just one instance of the Service class will be created. The single
instance is incredibly important as we cannot have different versions of the orders array doing the
rounds. Dependency injection is a design pattern that is implemented by Angular to solve the multi
instance problem that we could possibly face. You can read more on dependency injection here :
Dependency Injection (DI) design pattern: https://www.youtube.com/watch?v=OFPIGlxunL0.
https://angular.io/guide/dependency-injection

We will use the Injectable decorator to inform angular that we would like this service to be injected
into our components.
1.1. We will need to import the injectable module form @angular/Core

1.2. We next need to add the Injectable decorator to our class:

1.3. You will note that we state that the injectable is provided in root – this is because injectables
are hierarchical – if we want the service to be available though out your entire application you
need to provide the injectable at the root level. (See image below)

Figure 1: Courtesy of Angular.com

You can read more on how to use the hierarchical model here: https://angular.io/guide/hierarchical-
dependency-injection.

Once we have our Injectable imported and the decorator added we can go ahead and create the
methods that the service will be supplying as well as the array of posts that we will be populating
and in turn passing to the components that inject the service.

2. Create a private array named orders of type Order that will house our orders. Remember to
import the post model in order to use the Type Order
3. Next create a method that will allow the orders-placed component to get the placed orders :

We do not want to edit the array that will hold our posts - we want this array to remain perfectly
intact. BUT Arrays are reference types – this means that once we create an array in the ram – any
subsequent copies of that array we make will not actually create a copy but simply point the same
area in the RAM where the array was created. ( See the image below which shows ho array ia and ib
actually point to the same data.

99

Figure 2 courtesy of cngincdata.com

We need to create a true copy of the array with […this.orders] the three dots (…) is a java feature
known as the spread operator. It allows us to create a copy of an array and not just a copy the
memory address of the initial array. You can read more on the spread operator here :
https://zendev.com/2018/05/09/understanding-spread-operator-in-javascript.html

This practice of keeping the original array in its original state throughout the application is called
being immutable you can read more about that here: https://www.baeldung.com/java-immutable-
object.

4. We next need to create the method that will allow us to add orders to our system. Add the
following code to your application:
We are telling this method that we We then create an object of type Order ( store it as
are expecting a user name, e mail a constant) and assign the string values passed into
address and placed order as the method as arguments to the constant. We then
parameters. use the push command to push the object into our
orders array

Using the service to receive orders in the orders-placed component :

We would like our orders passed to order-placed component when the component initializes. We
will need to make use of lifecycle hooks to do this. Angular has various life cycle hooks that makes
the life cycles of an android component visible, we can then interact with these life cycles and write
code that we would like to execute when the event is triggered. Each component has a life cycle
that is managed by Angular. Angular will :

• Create
• Render
• Render children
• Destroy

The life cycle hooks for you. These hooks are implemented as an interface which will force you to
implement it’s corresponding method:
Figure 3Angular Life Cycle Hooks: Image Courtesy of C#corner.com

Using Lifecycle hooks to prevent memory leaks.

We will be making use of the ngOnInit and ngOnDestroy life cycle hooks. ngOnInit is implemented
as an interface which in in turn implements the ngOnInit() method. This interface initialises the
component as well as set all input properties.

ngOnDestroy will clean up the component before it is torn down . It does this by unsubscribing from
any observables – this is incredibly important . If we do not unsubscribe from any observables we
will be creating a memory leak. This means that the memory that has been assigned to our system
and that could potentially hold log on information is never cleared and freed. Memory leaks are
easy to cause and easy to exploit. It is important to make sure that we consider memory leaks as we
code.

You can read more on memory leaks here :

https://stackoverflow.com/questions/20744207/what-is-memory-leak-it-is-a-performance-issue-or-
security-issue , https://www.owasp.org/index.php/Memory_leak

Let’s go and edit our controller to receive orders and output them.

1. We need to import the two lifecycle hooks that we plan to use in our application. Go to your
order-placed component and import OnInit and onDestroy from angular core:
2. We next need to implement the two lifecycle hooks as interfaces :

3. Remember that interfaces contain method signatures that we are forced to implement once
we implement the interface. We thus need to add the ngOnInit() and ngOnDestroy()
methods:

4. We need to place the necessary logic into these methods, but we cannot do so until we
import and inject our service into this controller. Go ahead and add the following code to
import the order.service.ts file:
5. Now that we have imported the file, we need to gain access to the methods stored inside
our service. We are going to make use of our component’s constructor in order to create this
component knowing that it needs to access our service. You can add the following code to
your component.

6. Passing our service into our constructor using the public key word will automatically create a
property for us to use to access the methods stored in the OrderService file. We are no
ready to get our posts from our form. But we need an array or any type of collection to store
our orders in. We thus need to create an array of type Order to store our orders ( verify that
you still have the OrdersModel imported into you component )]

Once you are sure that you still have the import. We will make use of the same orders array
that we did before :

You can now remove the @input decorator from your orders Array

7. Now that we have the orders array ready to store any orders of type Order – lets go ahead
and use the ngOnInit() method to store our orders in this array :

8. Now that we can get orders , we better go and use the service to create orders.
Using the service to create orders in the order- create component :

We next need to move to the order-create component to create orders that we will be passing to
the order-placed component. Open your order-create.component.ts file and edit it as follows:

1. We also need to access our OrderService here. We need to add it to our constructor just as
we did in the orders-placed component :

2. We will leave a lot of the code we previously had , we just do not need the event emitter or
the object to create our posts any more. Our Previous order-create component had the
following:

You can go ahead and remove:

• The event emitter import and the @Output ()OrderCreated = newe EventEmitter… line.
• Remove the constant (object) that creates the order
• Also remove the line that emits the order.

3. Your onAddOrder method now needs to access the addOrder() method that we created in
the service. In order to do this we edit this method as follows:

We access the orderService Service property to get access to the addOrder method that we
created , we then pass the values from our HTML form into this method once the user clicks
submit.

4. Just a reminder that we make use of ngForm and ngModel to collect our user input from
our form and send it to our component when the user clicks on submit
We then access the form data by creating an orderForm object of they NgForm – this will give us
access to all the data we labelled using NgModel in our HTML Form:

5. We can now remove all the two-way databinding entries from our app.component.html file :
6. We can also clear all the supporting code from our app-component.ts file:

7. ** Theoretically this should now work – we should be able to both add and get posts.
However it will not work because of the following:
a. If we look back at our Service by opening the oder.service.ts file we can see that
we create an empty orders array

b. We then make a copy of this empty array to get our orders – we never update the
array . This might seem like a silly idea – but it keeping the original array in tact is
a good design practice.
c. We then call the getOrder method and return the empty array to our component.

We need to add another step to this application in order to update the array before we send it to
the component. The best way to do this is to make use of an observable.

Making use of the Observable design pattern to update and pass data between
components :

Observers pass data between publishers and subscribers – if we consider the image below we can
say that our HTML form provides as the data to store in our order array(contained in the order-
create component) (DATA PROVIDER) that we need to pass to the order-placed component. We
thus need the OrderService act as our observable that will push the updated data from the array(
filled in the order-create component ) to the orders-placed component who will act as a
SUBSCRIBER/OBSERVER

HTML / order- Order


create Service
Component

Order-placed
Component
We get the data from the user input in our HTML Form

It is passed to our service by our component calling the service’s addOrder() method:
Our service exports and updated array as an observable
Our order-placed component then subscribes to the Observable in order to get the updated array :

Create the observable :

1. Open your order.service.ts file and edit it as follows. We firstly need to import the Subject
module from the rxjs framework. Subjects takes the notification from the observable and
forwards it to one or more observers/subscriber. You can read more on subjects here:
https://blog.angularindepth.com/rxjs-understanding-subjects-5c585188c3e1

In our case the Subject will send the notification that the array was updated from our service
(observable) the order-placed component (observer/subscriber)
2. Add the following code to create your Subject that we will use to notify our subscribers:

3. Next add the method(getPostUpdateListener()) that will notify the order-placed component
that the array was updated:

4. Your service should now look like this:

import { Order} from './order.model';


import { Injectable } from '@angular/core';
import {Subject} from 'rxjs';

@Injectable({providedIn: 'root'})
export class OrdersService
{
private orders: Order [] = [] ;
private updatedOrders = new Subject<Order[]>();

getOrders()
{
return [...this.orders];
}

getPostUpdateListener()
{
return this.updatedOrders.asObservable();
}

addOrders(userName: string , Email: string , PlacedOrder: string )


{
const order: Order = {userName : userName , Email: Email, PlacedOrder:
PlacedOrder};
this.orders.push(order);
this.updatedOrders.next([...this.orders]);

We are using our observable to push the updated orders array to the orders-placed
component. We use the next key word. The next keyword actually calls a next() method that
will push the data to any subscriber that subscribes to this observable. (remember that
updatedOrders is our subject)
Create the Subscriber :

Now that our observable is ready to use the subject to push data to our subscribers , we need to
subscribe the order-placed component to the services observable.

1. Import the Subscription module from the rxjs package

2. We next to edit our ngOnInit() and ngOnDestroy () methods according to the following:

import { Component , OnInit, OnDestroy} from '@angular/core';


import { Order } from '../order.model';
import { OrdersService } from '../order.service';
import {Subscription} from 'rxjs';

@Component({
selector: 'app-order-placed',
templateUrl: './order-placed.component.html',
styleUrls: ['./order-placed.component.css']
})

export class OrderPlacedComponent implements OnInit , OnDestroy


{
orders: Order [] = [];

constructor( public orderService: OrdersService){}


private ordersSubscription: Subscription ;
1.

ngOnInit() {

this.orders = this.orderService.getOrders();
this.ordersSubscription = this.orderService.getPostUpdateListener()
.subscribe((orders: Order[]) =>
{
this.orders = orders; 2.
});
}

ngOnDestroy()
{
3.
this.ordersSubscription.unsubscribe();
}

}
1. Create an instance of your subscription in our case we are calling this instance
ordersSubscription:
2. We then edit the ngOnInit as follows:

We then set our orders array to We set the subscription to get the
accept the updated orders array getPostUpdateListener() and to
from the getPostUpdateListener () subscribe to the observable we
create there

We are thus subscribing to the observable and receiving the updated orders
array and writing it to the array that we want to display on our HTML page.

3. We lastly use the onDestroy() method to unsubscribe from the subscriber in order to avoid
any memory leaks.
4. We now have the following process in place:

Data Provider

Observable

Subscriber

5. If you now run your application you will be able to use the Service, Observables and
Subscribers to create and list posts:
You can learn more about Rxjs, Subjects, Observables and Services here:

https://yakovfain.com/2017/08/28/rxjs-essentials-part-1/

https://blog.angularindepth.com/rxjs-understanding-subjects-5c585188c3e1

https://angular.io/guide/observables
Adding Node JS and Express

Client and Server side validation for secure applications:

In the past it was somewhat correctly thought that server-side web scripts or web apps that made
use of a server were more secure than those who make use of client side scripting such as good old
HTML and JS. The truth is that you need to implement security on both. You need to make sure you
have good input validation for your textboxes with immediate feedback on the client side and that
you protect your application from the server side. Below are two very good article’s that you can
read that explains whey an either or approach is not the best security stand point.

https://stackoverflow.com/questions/162159/javascript-client-side-vs-server-side-validation

https://www.developsec.com/2017/06/19/validation-client-vs-server/

Understanding RESTapi’s

REST stands for Representational State Transfer . REST api’s use the HTTP GET, POST, PUT and
DELETE requests to transfer data between servers and clients. This data can be anything from a list
of the beach tide tables, nutritional values of food for dieters, weather forecasts and so forth. The
HTTP Request is often made to server for this data. The server will then send the client the data in
JSON format. The client can than format and output the JSON as he or she chooses. Think back to
the weather app you wrote using a RESTapi in OPSC7312. You can read more on RESTapi’s here:
https://searchmicroservices.techtarget.com/definition/RESTful-API

We are now going to set up our Node JS server and crate our own RESTapi for our clients. Our Api
will return a JSON object which contains User Names, e mail addresses and Orders posted. It is
important to make sure that we secure this connection as the data passed can be sensitive. We will
secure the data transfer last by implementing TLS( Transport Layer Security using the PKI framework)
For now we need to set up and work with our Node JS server.
Create the backend folder and server.js file.

1. Access your project through Windows Explorer and create a folder called backend: We are
going to create a separate server that will not serve our SPA Angular front end. We will still
use ng serve for that. In order to make sure that we separate the two – we will make use of a
completely separate folder.
2. Next create a server.js file on the root of your project. Your project might default the server.js
file into the source folder. You can simply drag the folder to the root of the project just above
the readme file:

Create your first Node-JS server:

1 .We need to run this server in a new console window , because we want to keep ng serve
intact. Click on the plus next to your current PowerShell console to start a new console:

3. Nothing will happen if we run this file now, but we would like to see if our server is working.
We are just going to out put the word hello: Add the following code to your server.js file
3. You should see the output in your console window if you re-run the file:

4. We now need to create a full Node JS server. To do this, we need to import the http package
that is installed by default when you install Node JS. Edit your server.js file according to the
following.

4.1

4.2

4.3

4.1. The syntax indicated above is used to import the http package. We store this package as
a constant (because we won’t be changing it) . We then use this package to create our
server.

4.2. We create another constant named server and set it to the server that we create with
the http package. This package has a built-in function that allows you to create your
Node JS server as well as pass in some HTTP Requests and HTTP Responses. In our case
we will hard code in a response that we would like the server to return to the browser.
You will notice a strange function being passed as a parameter into the
http.createServer method : ()=>{} . This strange function is known as an ES6 arrow
function. It allows developers to write concise powerful lines of code. For example:
The following is a normal ES6 method :

Figure 4 ES function: Image Courtesy of SitePoint.Ltd


This same method can be written as an arrow function as follows:

Figure 5 ES6 Arrow Function: Image courtesy of Sitepoint.Ltd

Thus the code below works as follows: please don’t ever use a layout like this – this is just to
explain where the arrow function fits in.

This outcome of this


Method
brackets
ES6 Arrow function being passed into
method is stored in the
http.createServer() method as a
server constant
parameter.

You might wonder what ES6 is ? ES6 is the 6th revision of a standard that Java Script was
built on. You can read more about arrow functions and ES6 here:

https://www.sitepoint.com/es6-arrow-functions-new-fat-concise-syntax-javascript/

https://www.quora.com/What-is-ES6

4.3. Lastly we invoke the listen method on our server constant. We need to pass the port on
which the server will listen and reply to request to into this method as parameters. Two
parameters are being passed in below. The first parameter should automatically pick up
the port of your hosting provider, the second as hard coded port number that we supply
in order to test our server.
5. If we now run the node command against our server , our server runs and we can access the
hard coded output in our browser by entering localhost:3000 into the browser:

Understanding Middle ware:

Express is middle ware that allows us to chain an entire stack of events together. These events can
then be executed in a chain to formulate a response to a user, perform functions on data etc. Below
is an explanation of how express middle ware works. The best way to understand how this middle
ware functions is to implement it.

Adding the Express framework to speed up the development of our Node Server:

Building an entire node server up from scratch would be an incredibly tedious process. We can
install the express frame work which will give us built in logic to quickly and easily develop a
functioning Node JS server:

1. Run the following npm command in your terminal ( the one created for our new server.js
server and are currently using)
2. You will see the following code if your installation was successful.
3. We are going to build our entire express app inside the backend folder we created earlier.
We will then just import that app into our server and run it. One thing that you need to
understand about express is that express acts as middle ware between our application and
our server. Express will allow us to send requests, and formulate responses that we can then
use in our server etc. Create an app.js file inside your backend folder:

4. We next need to import our newly installed express packages into the app.js file. The import
works exactly the same as in the server.js folder. Edit your file as follows:

5. Now that we have our middle ware in place, we can start using it. Let’s create some
responses etc with express. First we need to create another constant that we will call app
and execute our imported express into our constant ( this will give us access to all the middle
ware discussed above.

6. We can now use the use keyword to access different sets of middleware: To create our first
set of middle ware that will return an http response AND call the following set of middle
ware with the next() function – add the following code to your app.js file:

The use method accepts three parameters ( in its most basic form). These are : We are using this
Req -to formulate an HTTP request, middle ware to
output the
Res – to formulate an HTTP response following
response
Next – to call the next set of middle ware if a chain of middle ware exists.

7. As you can see the above code snippet does have the next() function listed, it will thus call
the next set of middle where which you can add to your project as follows:
** note that the above code snippet does not have the next keyword – thus the code chain
stops here.
You can read more on the express middle ware concept here :
https://expressjs.com/en/guide/using-middleware.html

8. Now that our middle ware is ready, we need to wire it into our server. In order to do this, we
first need to export our app.js. Add the following code to do so.

This will export the entire set of middle ware for us so that we can use it in our server.

9. Now that we have exported our middle ware – we need to import it on the server side. Open
your sever.js file and add the following line of code:
a. Create a constant called app
b. Add the require key word and point to the relative file path of the app.

10. Pass the app into your create server method to run the app on your server.

11. Add another constant and copy the port you passed into the server.listen() method into that
constant.
12. Set your app to use port key word and port variable in order to access the correct port.
13. Set the server to listen to correct port :

14. Click on the console and press Ctrl + C to stop the server
15. Enter node server to restart the server
16. You should see the following output from the http response we created in the app.js file:

Installing and using nodemon to auto restart our server.

At the moment we have to stop and start our server to test every single change we made. This can
become quite cumbersome. Because of this we are going to install the dev only package nodemon.
Nodemon will allow us to restart our server when we save our files.

1. Stop your server and run the following npm command in order to install nodemon as a dev
only tool:

2. You will see the following output of nodemon has successfully installed:

3. The nodemon command will not be available in the console because we did not install the
package globally and we asked to use it for development only.
4. If we want to run a command in the console, we need to add a script. Open then
package.json file.
5. In the package.json file look for the script object/node and add the following line of code

6. Save your changes (NNB) you should now eb able to run the start server command
Using our Server to fetch or Orders.

We are now ready to use our server to fetch some fake orders ( as we do not have a database yet)
using the express middle ware that we created. Edit your app.js to file to the following:

1.

2.

3.

1. We are adding a path to use with our middle ware. This will allow us to use different paths
for different features of our application. in this case we are actually routing the user to
http://localhost:300/api/orders.
2. We then create an array called orders that will hold two fake orders for us. You will notice
that an ID was added. We will need the ID when start pulling data from our Mongo
Database.
3. We then formulate our http response using the res keyword, we also pass another function
in there called .json. The .json function will convert what ever we pass into it to a JSON
object. Because arrays are easily converted to json arrays – we can just pass the array into
our json function. We can however built very complex JSON objects. We are also outputting
a message that the JSON object orders was retrieved successfully.

4. We now need to run this app on our Node JS server. Luckily we have already wired the app
into our server in the previous section. We can thus just run our server : (remember to do
this in a new console/terminal

5. WE can now access http://localhost:300/api/orders. We should see that our JSON is being
sent to our browser.

Now that we are ready to work with our application and server – we need to secure the connection
between our server and client so that the data we send between the two can be encrypted. We will
be using OpenSSL for this.

Installing and using SSL (TLS) with our Node JS Express Server

OpenSSL is a toolkit that we can use to achieve TLS ( Transport Layer Security) this Toolkit
implements the PKI framework (Public Key Infrastructure) which implements Asymmetric
encryption, digital certificates and digital signatures to secure data being transferred between
servers and clients. You should have learned about this in your textbook during lectures. If you are
unsure of how TLS and the PKI works – please refer to the links below :

https://www.openssl.org/

https://www.docusign.com/how-it-works/electronic-signature/digital-signature/digital-signature-
faq

https://www.thegeekyway.com/symmetric-and-asymmetric-encryption/
1. We need to install OpenSSL before we can use it. You can find openSSL on the following link:

Install OpenSSL : https://slproweb.com/products/Win32OpenSSL.html

2. Follow the installation wizard and accept all the defaults. ACCEPT where to install the
OPENSSL package. You want to install the package in yourstudent#\AppData\Roaming.
This will give your profile access to the OpenSSL files.

3. Open a new console in Visual Studio Code. Your window will look like the window below,
mine will be slightly different because I don’t have a student number : For the rest of the
manual we will be using my account.

Yours:

Mine

1. Navigate to the OpenSSL -Win64\bin folder

2. Generate a private key using the openssl genrsa command.

3. You will receive the following output if you were successful.


4. You next need to generate a certificate signing request in order to sign your certificate with
your private key:

5. Complete the fields requested with dummy Data

6. Supply a challenge password

9. Now use your certificate signing request to sign your certificate with your private key:
10. Run the directory (dir) command to verify that your certificate and private key has been
successfully created.

The screenshots might not be clear enough for you to make out exactly what the commands are.
Here they are in text form.

Create private key .\openssl genrsa -out privatekey.pem 1024

Generate a csr (Certificate signing request) .\openssl req -new -key privatekey.pem -out
certrequest.csr -config C:\OpenSSL-
Win64\bin\openssl.cfg

Sign your certificate with your private key by .\openssl x509 -req -in certrequest.csr -signkey
using the csr. privatekey.pem -out certificate.pem

11. We now need to move the certificate and Key into our ADPS project folder. I am also moving
the key and cert into a separate backup folder which I will later encrypt. You need to be
incredibly careful with your keys and certificates – you would never just store them in a
random folder. Use the following commands to copy the keys out of the bin directory into a
exportedKeys directory.

Copy-Item -Path certificate.pem -Destination Copy-Item -Path certificate.pem -Destination


c:\users\ctill\documents\exportedKeys

Copy-Item -Path privatekey.pem -Destination Copy-Item -Path privatekey.pem -Destination


c:\users\ctill\documents\exportedKeys

12. We now need to move the keys into a folder labelled keys that we will create inside our
ADPS project folder.
13. We will now edit our server.js file to use these keys and turn our server using https. We first
need import the fs (file system) module in order to access the Windows file system. We will
also require https instead of http for our http constant.

14. We next need to tell our server where to find our certificates and keys :
15. Restart your server, you can now access it using https://localhost:3000/api/orders

http://programmerblog.net/nodejs-https-server/

Fetching posts using our Node JS server and the Angular HTTPCLIENT:

1. We now have secure data transmissions set up. We would now like to use an HTTP GET
request to pull dummy posts from our server into our app. We are going to start going to the
app.modules file and importing the HttpClientModule : Edit your app.modules.ts file as
follows:

2. Now that we have the Module imported, we need to add it to the providers array (just as we
have done before). Edit the providers array as follows :
3. We still want our service to handle getting and displaying posts to and from the
components. We will thus edit our service to use an http GET request to pull our data from
our server. (just a JSON object until we have a database). We first need to import the
HttpClient into our order.server.ts file :

4. We can use DI to inject the HttpClient into our service (even though we are injection our
service into our components. The injection works exactly the same as it did in our
components. We need to create a constructor and use that constructor to automatically
create a property of the HttpClient ( I have called it http) that we can use:

5. Next we need to replace the logic in our get method in order to pull data from our service.
We are going to use http.get() for this. Edit your method as follows: We are passing in the
path to our server(back end) and the route on that server that holds our data.

6. We need to update our model, you will notice that we added an id field to our JSON which is
not present in our model. Edit your order.model.ts file to include the id property :

7. You will notice that our addOrders() method is going to throw an error now. That is because
we never used the id field when we created our object. In order to supress the error we can
pass in id:null when we create the object – see below.
8. We can now be quite specific when we use our get request , we can specify exactly what we
will be getting from our server. If you recall our JSON object we created on the server
contains a message of type string and an order which is an array of type Order. We can pass
this straight into your get method using <> . We can tell the get request that it is expecting
an object {} which contains two properties , one is a message of type String, and the next an
Array of type Order.
9. Edit your get request method as indicated below:

10. We now need to notify our angular app that we have new orders that we would like to
display. Luckily the httpClient uses a built in observable and all we have to do is subscribe
to it. Angular will also tear down the subscription automatically for us. You can just
add.subscribe() to the get request. We will then use an ES6 arrow method to tell angular
what we want to do with the JSON we receive.

11. If you read up a bit on the httpClient (https://angular.io/guide/http) you will find that this
client I actually a full API that allows us quite a few features. For example the httpClient’s get
request will automatically convert our JSON to javascript. When we pass in the order Data
that we get via the GET request we get TS support and we can access exactly what we want
from the data that we received from the server.
12. We will pull in only the orders array using typescript and we write it to our empty array that
we previously created in the order.service. ts file.

13. Lastly, we would like to update our application that new orders have arrived (remember the
error we faced when we were simply copying over the empty array . We will thus make use
of the updateOrders update Listener that we created earlier to send a copy of the array that
contains the JSON that we pulled from the server.
14. This will throw an error because we are no longer returing any values from the getOrders()
method in the service. We use to accept orders from the service and then write it to the
orders array in the component. We will now change our code to simply fire the http GET
request every time the order-placed componenet loads.

15. In theory we should be able to retrieve our posts now, Unfortunatly no posts will appear .
When we right click on our angular app and select inspect we will see the following error:

This is known a CORS error . We will discuss what an CORS error is next and resolve the
issue.
Understanding CORS and using Headers to allow CORS

CORS stands for : Cross Origin Resource Sharing . We need to access CORS because our client and
our server lives separately. Our client lives on http://localhost:4200 and our Server lives on
https://localhost:3000 the origin of these two entities is not the same.

CORS is blocked by default by ALL web servers as a security feature. If the client does not originate
on the same server, it should not be able to access data from that server. But, what about API’s. we
have no control which clients make use of an API. Some might use a browser, some might be a
mobile app ? In cases like this we allow CORS using http Headers. Http Headers allow clients to send
additional information along with their request to the server. In this case, we will use headers to tell
the server to allow CORS. You can read more on http headers her : https://developer.mozilla.org/en-
US/docs/Web/HTTP/Headers and more on the headers we are using and CORS errors here :
https://daveceddia.com/access-control-allow-origin-cors-errors-in-angular/

1. We need to change our app.js file to use an additional piece of middle ware. This middle
ware will set the response http headers to allow course for us. We are setting extra headers
here that we will use later as well. Edit your app.js file with the following additional middle
ware.

const express = require('express');


const app = express();

app.use((reg,res,next)=>
{
res.setHeader("Access-Control-Allow-Origin", '*');
res.setHeader("Access-Control-Allow-Headers",
"Origin,X-Requested-With,Content-Type,Accept"
);
res.setHeader("Access-Control-Allow-Methods",
"GET","POST","OPTIONS","PATCH","DELETE");
next();

});

app.use('/api/orders',(req,res,next)=>
{
const orders = [
{
id: "2jofunisr3od",
userName:"molly_001",
Email:"[email protected]",
PlacedOrder: "Cheese Cake from server "
},

{
id: "2jofunisr3od",
userName:"molly_002",
Email:"[email protected]",
PlacedOrder: "Lemon Pie from Server"
}

];
res.json(
{
message: 'Orders retrieved from Server successfully',
orders:orders
}
);

});

module.exports = app;

if we look back at the error we can see that it clearly states No Access-Control-Allow-Origin
header is set.

2. Therefore we specifically set the header : we set the header Access-Control-Allow-Origin,


and because we are defining an api, we are using the * wild card character to allow access
from all domains.

Be sure to add the next() method to this set of middle ware, we need to run the request
middleware next or no posts will be added. You can read more on the other headers we added
here: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Methods
You will notice the X-Requested-With header there as well. This is an important header that is used
to protect from CSRF attacks. We are allowing multiple domains and clients from different servers to
connect to our app. This header will not be added to the AJAX request (AJAX works between clients
and servers) cross domain unless specifically allowed through CORS. We can define the headers that
we would like to allow cross domain. The following can be allowd:

• Accept
• Accept-Language
• Content-Language
• Last-event-id
• Content-Type

You can read more on this here:https://stackoverflow.com/questions/17478731/whats-the-point-of-


the-x-requested-with-header and for your POE I would recommend reading here:
https://markitzeroday.com/x-requested-with/cors/2017/06/29/csrf-mitigation-for-ajax-
requests.html

3. With our app.js file correctly set up, we should be able to see our orders : Save your changes
and relook at your localhost://4200 site
GET versus POST and the POST backend request:
You would have learned that GET requests are not secure as they append the data the are sending
between the server and the client to the URL. Post however has a message body in which it sends
the data. We have been using GET requests until now because we have simply been retrieving JSON
from our server, we now need to use more secure POST requests to accept input and pass it to our
server. You can read more about the difference between GET and POST here:
https://javarevisited.blogspot.com/2012/03/get-post-method-in-http-and-https.html

You can also watch the following YouTube Video which has a live demonstration:
https://www.youtube.com/watch?v=9o_4lsOkQ3g&t=327s

When we use POST requests, we need to get access to the data passed in the POST body. We install
an additional Node JS package known as body parser to provide us with extra middleware in order
to do so.

1. Stop your server from running by clicking on Ctrl + C and entering y for yes
2. Next enter npm install –save body-parser
3. You will see the following output if your installation was successful.

4. We now need to start creating our first post request in our app.js file: we are still using our
express executed into our app constant to create a post request. We still need to add the
path we want to follow as well as our ES6 arrow function . We now need to store the data
the user entered somewhere so that we can pass it to our order-placed component. We use
body parser to do that for us.

We firstly need to import body parser into our app.js file. We also want body parser to
convert the data the user entered to JSON – we therefore call the
app.use(bodyParser.json()) middle ware. Body parser uses the .json() method to extract all
the data stored in the body of the post request and then stores it in an object named
body.req. We can later call post.req in order to access our data.

4.1. You can read up more on body-parser here:


https://stackoverflow.com/questions/38306569/what-does-body-parser-do-with-express
Figure 6Body parser functions: Image courtesy of SOF

4.2. We can now create our post request and use body-parser to handle our data:

• We store the data the user entered that was passed to server with the http POST
method in a contant called orders using reg.body from body-parser
• We then output our orders to the server with console .log.
• We next register a status to show is that the process worked fine and that one order
was added.
• We use Json to output a message that the order was successfully created.

5. We now need to edit our addOrder() method in our Service so that we can add orders and
pass them along to the placed order component through the server.
5.1. We create a new http.post request. We again set the type that we will be retrieving, in this
case it is just a message that tells us if the order was successful.
5.2. We still have to add the path, but in this case we are indicating where the user posted the
data to so that we can get it from there : it is still https://localhost:3000/api/orders.
5.3. You will notice that we need to pass in the object that we would like to store the data that is
currently within the post request in. We are passing in our constant order. This means the
following will happen:

6. Right click on the APDS website and choose inspect – you will see our message which states
order successfully created. Do you see that the order service provided this message from the
code on line 36 ?
7. If we rerun our application now and enter an order, it should be passed to the server with
the post method, accessed and changed to JSON by body parser on the server. The JSON
data is then added to the order constant which is pushed to the orders array and displayed
by the order-placed component. The message is also logged to the console 😊😊
8. If you still encounter the error listed below when you try and create a post – make sure to
check the spelling of your headers in your app.js file.

Do you see CORS blocking the headers here ? Remember that this helps to protect your site from
Cross Site Forgery Attacks. (CSFR)
Adding Mongo DB to persist our Data

We are now ready to connect our application to a database in order to persist our data. We are
going to use a NoSQL database called MongoDB for that. NoSQL relies on JSON objects which are
nice and easy to work with in applications.

Registering for Mongo DB and Creating your Cluster

1. Visit the following link to register for the free MongoDB AWS could instance.

https://www.mongodb.com/

2. Click on the get Start Free option / or the Try free button. This will take you to the sign up
screen.
3. Register for a free cluster by completing the registration form.

4. Once you have registered you can go ahead and log in.
5. Once you have logged on you can click on Build a new cluster , also please set your time
zone

6. Click on AWS when the build a new cluster page opens. You will notice that the North
Virginia server is offering a free Tier Select that Server.
7. Scroll down to Tiers and select the free Tier from there (M0 – Free for ever)

8. Click on Create cluster – you will see the following screen while your cluster is being created.
(this might take a few minutes).

9. You should see the below screen when you cluster has successfully been created.
10. We need to add our root / admin user in order to access our Cluster – click on add User .

11. Create a new user with read/write access ( you can name this user what ever you want)
12. Auto generate a password for the user and keep it some where safe.
13. Your completed user should appear as follows:

14. We lastly need to add our IP address to the white list. Just like white listening the IP address
on the white list allows our IP address through the firewall to connect to our database.

** Note that campus IP address and your home IP address is not the same. You will need to update
the IP address if you are working on your project at home. ALSO ISP’s “rent out” an IP address to
you when you connect to the internet. The IP address you get is not always the same – if have
strange connectivity issues – update the IP address again.
15. You can just click on ad current IP address to whitelist your current PUBLIC IP address.

16. Click on Confirm to complete the process:


Adding Mongoose to our App:

MongoDB and most NoSQL databases do not use database schema’s. A schema is blue print of the
structure that your database will follow. We can then create models based on these schemas. The
orders that we are creating are quite structured. Every order we place or display contains:

• UserName
• Email
• PlacedOrder

We can probably benefit from a schema and use it with our model. In order to do this, we need to
add a nother Node JS packages known as Mongoose. Mongoose provides schema’s and models for
MongoDB databases. You can read more on Mongoose here: https://mongoosejs.com/

1. We need to install mongoose in order to use it – we can run the following command:

2. You will see the following output once Mongoose has successfully installed.

Building Mongoose Models:

We can now use Mongoose to build our models and schemas. Our backend will be handling the
communications between our app and MongoDB for us. We will thus create and use our models in
the backend folder.

1. Create a new folder called model in our backend folder.

2. Create a new file called order.js inside the model folder.

3. Open the order.js folder and import mongoose


4. We can now use mongoose to create our schema. Remember that the schema is the
blueprint of what our database will contain, it specifies what fields the db/table will contain
as well as what data is in that filed. A model is a high level representation of the tables in
that database. You can read more on Schema’s and models here :
https://softwareengineering.stackexchange.com/questions/286597/difference-between-
data-models-and-schemas , https://stackoverflow.com/questions/25093452/difference-
between-data-model-and-database-schema-in-dbms

5. We will store our schema in a constant named oderSchema. We make use of the mongoose
Schema object to define a JS object that represents our data. Mongoose also provides us
with additional features, for instance we can mark the fields as required. You can read more
on how mongoose uses and manages schemas here:
https://mongoosejs.com/docs/guide.html

We are defining a schema , here we state that our schema will hold different properties (
userName, Email etc) and that these properties will contain data of type string. We also use
The mongoose schema method to set the fields as required. This should feel a lot SQL by
now

WE can pass this entire object {} into our schema

6. Now that our schema is ready, we can use it to create a model. We will use the mongoose
model() method. We just need to pass in the name of our model as well as the schema that
his model will be based on.
We are using the Name of model Schema we are
mongoose model passing in
method ()

7. We would also like to use this schema outside of the order.js file . We will make use of the
module. Exports() method to export the model so that we can use it in app.js
Creating an instance of and using our Model

We now have our model ready to use in the app.js file.

1. Import the model into your app.js file :

2. We now want to use our model when ever the HTTP POST method is called ( this happens
when an order is added) We want to access the data passed to us in the post body and send
it to the orders-placed component through our service. We will edit our post middle ware as
follows:

WE instantiate our This order will then be The post is displayed by


orders model and passed through our service the orders-placed
use body parser to to the order-placed component.
assign values to fields component
in the model
3. When this is complete – we can create and a view a post using our Node Server

https://devcenter.heroku.com/articles/nodejs-mongoose

4. Below is the post that we logged using console.log, do you see that the ID field is auto filled
for us ?

5. Now that we can accept our user input through a POST request(express), then convert it to
JSON (body-parser) and then output this JSON to our angular UI (front- end), we are ready to
send our orders straight to our MongoDB .
Connecting our App to the Mongo DB:

We will need a connection string in order to connect to our Mongo DB Cluster. We will then start
storing (persisting) our data on the Database.

1. Log onto the Mongo cloud platform. Click on our cluster, then click on connect:

2. THis will open the connect to cluster page : We want to connect our application to Mongo,
click on Connect your appplication.
3. Make sure that you select Node.js and the latest version of the driver. – this will generate a
connection string for you. Copy this string.

4. Now that we have our connection string, we are ready to connect to the database. Open
your app.js file. We are going to use the mongoose.connect() method to connect to our
database. Add the connection string that you have just copied right underneath the line
where you created your express app:
5. Replace the password with the password of the user we created earlier (you had to keep it
safe remember ?)

6. The mongoose connect method allows us some extra functionality such as the .then()
function. The connect method is actually a Java construct known as a promise. A promise is
an object that is return by an Asynch process. A promise can be in one of three states:
• Fulfilled
• Rejected
• Pending
A promise is settled when it is either fulfilled or rejected. Promises have a then() function
which tells Node what to do when a promise is either rejected or fulfilled. In the code above
mongoose is making a promise that it will connect to the database for us ( by using a
promise object, which actually has a promise constructor that has resolved() or rejected() as
parameters). We will use the then() method to tell mongoose what to do when either
resolved() or rejected() returns true.

You can learn more about java script promises and the built in Mongoose promises here:
https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-promise-
27fc71e77261 & https://mongoosejs.com/docs/promises.html

7. We are now editing our connect method to use the .next() method as well. We are passing
in a ES6 arrow method for the resolved() method which will write a success message to our
console. We are passing in another ES6 arrow method that will log a failure message to our
console into the rejected() method.
8. We should now be able to receive a successful message when we restart both servers (
Remember to do this in separate consoles ) Restart the angular app with ng serve and
restart the node Sever using nodemon. You should see the following output logged to your
console :

Securing the connection to our Cloud instance of MongoDB with SSL (TLS):

Now that we can successfully connect to our database, we need to secure the connection to the
Mongo-DB as well as secure our Angular Front end. We will set both of these to run over SSL using
the certificates and keys we created earlier:

1. Open your app.js file and edit your code as follows:

We need to import the We store the path to our We set our options to tell
file system module in certificate in a constant the server that it needs to
order to access files named cert use our certificate as the
stored in Windows certificate Authority
2. Since we now have our connection to Mongo Running over SSL as well as our Node Server
serving pages over SSL. It is best to set our angular to run over SSL :

3. You might get the following error ( this indicates that your browser does not know/ trust the
certificate you are using) This is because the certificate and CA that created it is not added to
any certificate store on your machine. It does however indicated that you are serving pages
over ssl 😊😊.
You can learn more about configuring SSL connections here:
https://medium.com/@rubenvermeulen/running-angular-cli-over-https-with-a-trusted-certificate-
4a0d5f92747a and here: https://scalegrid.io/blog/mongodb-ssl-with-self-signed-certificates-in-node-
js/
We are now connected to our database and ready to store our orders on it.
Writing orders to Mongo DB:

We will be using Mongoose to allow us to save our orders to the Mongo DB. We first need to make
sure that we are writing to the correct database. The connection string you receive from the Mongo
website will automatically create and write to a test database. We do not want to call our database
test, we will thus change our connection string to automatically create a database with a name of
our choosing.

1. Change your connection string to contain the name of the database you would like to create.
Mongo will automatically create the database for you and assign it the correct name when
we connect to it for the first time.

2. Now that we have our database ready we can store our posts in the database. This is
incredibly easy – we simply add orders.save() to our post request. Mongoose will take our
orders model and automatically save the data the user entered into the database.

3. We can now go and test it out. We can access our Angular front end and create an order: I
used the user name dbtest, and the e mail [email protected] and added testing our db as
the order.
4. MongoDB does not have an interface that we could use to go and check if our orders have
been added to the database. We will need to download the Mongo Shell and use this in
order to verify the persistence of our data.

5. Log onto the MongoDB site and click connect on your cluster :

6. Click on the Connect with the Mongo Shell when the Connect to Cluster0 page opens:
7. You need to select the correct operating system in order to download the Mongo Shell.
Select the correct Operating system and click on Download Mongo Shell (the latest version)

8. I have selected windows and I am downloading Mongo Shell version 4.0.6.


9. Extract the zip file once the download is complete.

10. Copy the content of the zipped folder and save it in a folder that you created any where on
your system. I am copying my files to a folder called shell inside my documents in a folder
badly labelled ADPS (too late to change it now !):

11. You are going to need a connection string to connect to your database. Go back to the
MongoDb website and copy the connection string provided by the connect to shell page:
12. Open a new terminal in Visual Studio code and enter .\ before you copy over the connection
string . The shell will connect to your cluster and request your password. Enter the
password that we created previously.

13. The server will make a connection to your cluster to allow you to query the cluster.

14. We can now enter the use command in order to connect to our database. The system will
inform us that it has switched to the correct database.

15. We can then enter show collections in order to see the collections stored in the database. As
you can see – the system lists orders.

16. Lastly we can show or order by running db.ordres.find(). This command should display the
contents of our order stored on the server.
Reading Orders From Mongo DB:

Now that we are able to post our orders to the Mongo Cloud DB, we can add the code to retrieve
the data. We will be making use of Mongoose for this. Mongoose has a wide range of queries that
can be run against a Mongo DB . We will be focussing on a single query here. You can read about all
the available queries from here :https://mongoosejs.com/docs/queries.html

1. We need to change our previous use request that displayed hard coded data into a get
request that will enable us to pull data from our Mongo DB. You will remember that we
imported our model as Order in order to use it in the app.js file.

2. We are now going to use one of the built in queries supplied to us by the Mongoose Model
function. We will run Order.find(). Order to find will pull a list of ALL the orders saved on our
database. There are better queries to use , which we will look into later. Edit your app.use
request in the app.js file to the following app.get() request.
In the above image we use the find() method to find all the “documents” of orders stored in the dB
(documents = JSON objects). Once we find the documents we use the then function to indicated what
would like to do if the documents were successfully located ( similar to a promise as discussed
above). In our case we would like to transform the response to JSON, output a message that will let
us know that the orders have been successfully retrieved and store all the “documents) in the orders
object.

Below are two screenshots indicating that we can read and post the server :
Deleting Orders from Mongo DB:

We would also like to delete Orders from our Database. Unfortunately, we will need to access an ID
for each post, how else will we know that we are deleting the correct post? We know that the
database will automatically assign each post an id:

1. We will need to amend our code in order to make use of this id. Let’s start by adding an id
field to our model:

2. You will notice that the ID returned by the MongoDB labeled as _id: We would like to access
this id but we do not want to change our module to use _id ( we will be making use of the id
field quite a bit and keeping it as id would simplify the processes that follow). Luckily, we
can transform the data given to us by the database. We will do this in our service
(order.service.ts) file.

3. We will need to import the map operator from rxjs. The map operator will allow us to
iterate over the data stream ( an array in our case) provided by the httpClient. We can then
change each element in that array before any observers subscribe to it.
4. We also need the pipe() function in order to use the map() operator. The pipe() function
allows us to use operators on an incoming data stream ( the http response body in our case.
[This body is conveniently an array]). Edit your code as follows :

5. Apply the pipe() function to your get request. Then pass the map() function into the pipe
function.

6. As mentioned above, the map() function allows us to apply a method or change each
element in the Get response array and save it to a new array. We thus pass the orderData
(response body) into the map method and then use the map method to change each
element to a JS Object that contains the correct id.

You can read more about the above functions here :

http://www.java67.com/2015/01/java-8-map-function-examples.html

https://stackoverflow.com/questions/20085513/using-pipe-in-node-js-net

https://blog.angularindepth.com/reading-the-rxjs-6-sources-map-and-pipe-94d51fec71c2

https://angular.io/guide/http#observables-and-operators
7. We need to amend our form to contain a delete button and then add the delete function to
that button. Lets change the form first :

8. We should see the following when we save our changes and view the page:
9. We next need to create the deletePost() method in our service. Open your order.service.ts
file and add the following:

1.We create the delete


order method and pass
in the orderID as a
parameter.

3. Remember that the httpClient returns a 2. We next use the httpClient to create
observable that we can subscribe to . In an http Delete request routed to our
this case we are logging a success message orders- we provide the ID of the post
that we want to delte

10. Next we need to tell our server that we would like to delete a post with a certain id. Edit
your app.js file to match the following.
11. Lastly we need to ensure that the delete request is allowed. We need to change our CORS
headers to allow all Access- Control-Allow- Methods

12. If we now open one of our posts and click on the delete button, we should get a console
message (right click inspect ) indicating that the order has been deleted.
Adding Routing to better Navigate our App:

We need to use routing (links between pages) in order to make our application more user friendly
and accessible. We will be using angular routing to change our application to look as follows :

Each of the links above is connected to an Angular route that will allow us to navigate this page
much easier. We will be configuring these routes as follows:

1. Create a new file inside the app folder and call it app-routing.module.ts

We call this file app-routing.module.ts because it is good practice but also becausew e need to
create a new module which will handle our routing ( We could add our routes to the app.module file
, however it is good practice to separate out your concerns so that your application is easy to
maintain and update - we are thus creating our own module)
2. We need to import the NgModule module in order to decorate this file as an NgModule. We
also need to call in the Routes and RouterModule modules from @angular/router. Now that
we have our imports complete , we can go ahead and create some routes.

3. We need to create a constant named routes. This constant will contain an Array Java Script
objects that needs to be created in a specific manner. Each one of these objects needs a
path property as well the component that needs to displayed at this given path. Lets take a
closer look at the two components listed here:

We are passing an empty value in for


the path property– this means that
the component listed after the path
will display when the page first loads
and there is no slash present :
Localhost:4200 and this case the
OrderPlacedComponent should
display

4. If we look at the page when it loads , we will see that the URL is https://localhost:4200 with
no slashes behind it and that the OrderPlacedComponenet is displaying:
5. If we look at the second entry we see that the path property contains a create entry, this
will append /create behind our app’s domain (localhost:4200) and display the
OrderCreateComponen (localhost:4200/create).

6. If take a look at our application after we clicked on the create button , we will see that the
URL is now https://localhost:4200 and the OrderCreateComponenet is displayed:
7. If go ahead and create an order, it should then display on the landing page:
8. Our app-routing.module.ts file now contains the two routes that we would like to use. We
now have to use these routes on our front end. We need to make angular aware of our
routes before we can do that. Do to this we add the following to the app-routing.module.ts
file:

https://angular.io/guide/router

Lastly, we need to register our appRouting module in the imports array of the app.module. ts file:

Make sure that your IDE automatically imports the path to the app-routing.module file .

We can now access our app.component.html file to add the routes to our buttons:
PART C
Adding Authentication:

Ours system is now able to accept , store, delete and edit orders. We need to start securing this
system better by adding authentication. We will require our users to sign up and login. In order to do
this we need to create the Auth folder which will contain our Login and Sign Up components. Create
the followings folder structure in your project:

We will be starting with the login component , make sure that you create the login.component.html
file as well as the login.component.ts file (Just as we did for all the other components).

Creating the Login Form:

1. We are going to copy over and edit the form we initially created for the order-create
component. Copy the form into your login.component. html file and edit it as follows:

2. <p>Please Log in </p>


3.
4. <mat-card>
5.
6. <form class = "login" name = "login" #loginForm="ngForm" >
7. <mat-form-field>
8. <input matInput type ="text" ngModel name="enteredUserName"
9. placeholder ="User Name"
10. required
11. minlength="8"
12. pattern ="^[a-zA-Z0-9\s_-]+$"
13. #enteredUserName ="ngModel"/>
14. <mat-error
*ngIf="enteredUserName.invalid">{{enteredUserNameError}}</mat-error>
15. </mat-form-field >
16. <br>
17. <mat-form-field>
18. <input matInput type ="email" pattern ="^[\w-\.]+@([\w-
]+\.)+[\w-]{2,4}$"
19. ngModel name ="enteredEmail"
20. placeholder="Email Adrress" required
21. #enteredEmail ="ngModel"/>
22. <mat-error
*ngIf="enteredEmail.invalid">{{enteredEmailError}}</mat-error>
23. </mat-form-field>
24. <br>
25.
26. <mat-form-field>
27. <input matInput type ="password" pattern ="^([a-zA-Z0-
9@*#]{8,15})$"
28. ngModel name ="enteredPassword"
29. placeholder="Password" required
30. #enteredPassword ="ngModel"/>
31. <mat-error
*ngIf="enteredPassword.invalid">{{enteredPasswordError}}</mat-error>
32. </mat-form-field>
33. <br>
34. <button mat-raised-button type = "submit" >Login</button>
35. </form>
36. </mat-card>
37. <hr>
38.
39.

3. You will notice that there is a new regex pattern added to the password field – this pattern
was taken form the regex library – you can find the pattern I used by clicking on the below
link. This regex pattern conforms to basic password complexity. It is possible to create a more
complex password but it might have an impact on the usability of your system.

http://regexlib.com/Search.aspx?k=Password&c=-1&m=-1&ps=20

This form will work exactly the same as the order-create form that we created earlier in this guide,
please refer to that section if you are unsure of any of the configuration.
4. We next need to add our error messages that we are displaying using string interpolation ,
we need to edit the login.component.ts file to contain our error message string values. We
also need to add the component decorator and the styleTemplateUrl to the component
decorator in order for Angular to register this file as a component. Edit your
login.component.ts file as follows:

4.1. Create your LoginComponent Class.

4.2. Add the component decorator and next add the templateUrl (our html file that we are using
to display our form )value to the decorator ( You will notice that the Component decorator
has a red squiggly line underneath it. It also requires a login.componet.css file - you can add
this if the error bothers you.

4.3. We next need to register this component in the app.component.ts file – add your
component to the declarations array and Visual Studio Code will create the necessary import
for you ( verify that it does).
4.4. You can now copy over the error messages from the order-create.component.ts file and add
an error message for a poorly formatted password field:

Creating a Route for the Login Form:

1. We next need to allow the user to navigate to the login form. We will need to add a route to
this form. We do this by adding the route the routes array in the app.routing.module.ts file :

<

2. Make sure that your component is imported into the app.routing.module.ts file:
3. Lastly we need to ensure that we can access the Login Page using our route. We will add a
button that uses our route and the routerLink function in our app.component.html file.

4. If we save our changes and reload our application we should see the following:
5. Click on the Log in button and you should see your login form :

6. We lastly want to start testing the functionality of our Log in Form – we will need to sing up
a user to be able to do that.
Adding the Sign up Functionality:

1. We can now create our Sign-up Component. We will make use of a lot of the logic that we
have already created for the login component. Firstly We will need to create the
signup.component.html and the signup.component.ts file (this should start feeling familiar
by now).

2. Copy over the HTML form we created for login, but edit it so that it has fields for :

**Take noet of what you name your input fields NgModel name =”enteredUserName is the value we
will be using.

a. userName
b. Email
c. Password
3. We next need to hook up our logic with the singup.component.ts file. We will re-use most
of the error messages that we used before (for order-create.component.ts and
login.component.ts). We will also add a custom error for our new password field:
4. We will also create an onSignup method that accepts ngForm as a parameter (exactly the
same as we did for our create order form) We will only log the contents of the webform for
now.
5. We next need to make sure that we add links in order to see our sign up option. Edit the
app.routing.module.ts file to include the signup route.
6. Now we can edit the app.component.html file to include a button for our sign up:
7. Register your component in the app.module.ts file

8. If we now restart our application we should see the following:


Creating the Add new user Back end and hooking it up the Front end:

Now that we have the Sign up function created on the Front end (Angular) we need to create the
back end POST request and routes in order to save (register) new users to our database. We now
have to definite routes in our application. The one route (hyperlinks )directs the user to create
orders and the very next route directs users to create user accounts.

We currently have all our routes in the app.js file. This can become problematic when we have a lot
of routes. It is also important to maintain the separation of concerns principle that we learned
earlier. We are therefore going to rework our backend a bit in order to be better equipped for a
more scalable application.

1. Our backend already has a model folder that contains the order model that we used
previously with mongoose (revisit this section if you are lost). We are going to add a routes
sub folder that will be dedicated to handling our routes and separating out different routes.
We will create an order. js file that will handle all the routes requesting or sending
information to any URL that starts with /orders and we will also create a user.js file that will
handle any requests for information to or from the /users route.

2. Create the following files and folder in your backend folder:

3. We can now move all our post and get requests that target the /api/orders URL from the
app.js folder to the order.js folder. We will also make use of the built in express Router
module to handle our routing from here:

4. Add the following imports to your order.js file:

const express = require("express");


Notice the import
const router = express.Router(); for the express
Router module
const Order = require('../order')
router.post('',(req,res,next)=>
{
const orders = new Order(
{
userName : req.body.userName,
Email: req.body.Email,
PlacedOrder: req.body.PlacedOrder

}
);
orders.save()
.then((createdOrder)=>
{
console.log(createdOrder);
res.status(201).json({
message: 'order successfully created',
orderID: createdOrder._id
});
console.log(orders);

});

});

router.get('',(req,res,next)=>
{
Order.find().then((documents)=>{
res.json(
{
message: 'Orders retrieved from Server successfully',
orders:documents
});
});
});

router.delete("/:id",(req,res,next)=> We can now use the


{ express router instead of
console.log(req.params.id); the express to handle our
Order.deleteOne({_id: req.params.id}) HTTP Requests.
.then((result)=>
{
//console.log(result);
console.log("Order Deleted from DB");
res.status(200).json({message: "Order Deleted from Database"});

});
});

We can then export this file and


module.exports = router;
import into our express app (app.js)
so that our server can use the routes
(HTTP REQUESTS aimed at a specific
URL that we created.

9. We now need to edit the user.js file stored in our routes folder to create the appropriate
HTTP REQUESTS / Routes for our user account functionality. Import the following into your
user.js file.

10. We now need to create a model for users using Mongoose , we will follow the exact same
method as we did when created our orders model. Go ahead and create the user.js file in
the backend\model folder and create the following module
Adding Backend Post Request to create users and store them in Mongo DB:

We are now ready to add our POST request in order to create our user and store the user in our
Mongo DB. We do however need to consider how to do this securely from the start. We are using
regex in our HTML form to enforce a strong password. HOWEVER, we cannot store our passwords
in plain text. This would mean that any person who gets access to our DB would be able to see and
use all the passwords( users often re-use passwords). We will be using bcrypt to encrypt (hash) and
salt our passwords before we store them in our DB bcrypt uses blowfish as a hashing algorithm
(cipher) you are welcome to read up on the strength of this algorithm, it is impressive. We will store
the salted value and compare a salted value. Let’s install bcrtypt first:

Stop your sever


and add the
following line

1. We can now go ahead and create our POST request. We will once again use router.post and
provide the link that we are supposed to follow. “/signup” in our case. (please refer to
previous sections where we created the post order request if you are lost). The difference
here is that we need to make use of bcrypt to both hash and salt our password. The image
below shows you how to use the bcrypt hash() function in order to hash the password that
the user entered. You will also note that an int value for saltOrRounds is needed. This will
add the needed salt to our password. We are using 10 rounds.

2. Make sure you import brcypt.

You can read more about bcrypt here:

https://medium.com/@mridu.sh92/a-quick-guide-for-authentication-using-bcrypt-on-express-
nodejs-1d8791bb418f
Bcrypt has function that
will hash our password
using blowfish

3. Our completed post request in the user.js file will look like this:

Bcrypt import

Note that we are storing the


salted hash into our
database

We need to export our


routes so that we can use
them in the app.js folder.
4. App.js will now look like this:

const express = require('express');


const mongoose = require('mongoose');
const bodyParser = require('body-parser'); We import both
const fs = require('fs'); the user and
const orderRoutes = require("./model/routes/orders"); order routes here
const userRoutes = require("./model/routes/user");

const cert = fs.readFileSync('keys/certificate.pem');


const options = {
server: { sslCA: cert }};

const app = express();

mongoose.connect("mongodb+srv://SamAdmin:D47fLwhCiLGrYYxM@cluster0-
glieu.mongodb.net/order-system?retryWrites=true")
.then(()=>
{
console.log("connected to DB successfully ! YAY")
})
.catch(()=>
{
console.log('Apparently not !!!')
},options);

app.use(bodyParser.json())

app.use((reg,res,next)=>
{
res.setHeader("Access-Control-Allow-Origin", '*');
res.setHeader("Access-Control-Allow-Headers",
"Origin ,X-Requested-With,Content-Type,Accept,Authorization"
);
res.setHeader("Access-Control-Allow-Methods",
"*");
next();

}); We use these routes here : you will note that we tell
angular that we want to use the orderRoutes object
for any requests to /api/orders and the userRoutes
object for any routes to /api/user express will then
app.use("/api/orders",orderRoutes) append the Post /delete/get routes to create a full
route such as: /api/user/signup
app.use("/api/user",userRoutes)
module.exports = app;

Connecting the Front end to the back end:

1. We will need to create a service that we can inject into both our login and signin typescript
files (.ts). Navigate into the Auth folder and create the Auth.service.ts file :

2. You can refer back to the section where we created the order service if you are confused.
Please go ahead and create your authentication service according to the following:
5. We will also need a model (just like before): Create the auth-data.models.ts file inside your
Auth folder

6. Populate the file as follows:


7. We now have all the piece to create a new user and store them on the Mongo DB.
8. If we save our changes and access the sign up page – we should be able to create a new
user:

9. If we inspect our site we will notice the following:

Created by our log in our signup


component file : Note the password

Created by our auth service which uses httpClient to


create a post request to link our back and front end : Note
the password which has been hashed and Salted 😊😊

10. We can no successfully create and store user accounts with salted and hashed passwords.
Understanding Single Page Application (SPA) Authentication:

We are now able to create user – we would now like to log that user in. We need to understand
how user Authentication works in SPA’s:

Remember that we currently have two servers – one serving on https://4200/orers or users and one
server that serves on https://3000/api/orders or users. You will remember that we basically created
a REST API on our backend node.JS server (much like the REST API’s that you have been using in
Angular – this api sends information to our front end application that runs on https://4200. These
two servers are completed disconnected ( we just run them in the same VS Code project because it
is easier ) A graphical representation of what our architecture looks like would be :

Localhost:4200

Localhost:3000

Figure 7;Image Courtesy of medium.com


We can further define our graphical interpretation as follows :

1 SPA (Angular Application)

uses

2 HttpClient

To request using
an HTTP Request
either to get or
3 GET/Orders post orders POST/Orders

4 Node JS server (REST API)

1. We have an independent SPA that could run in a web browser, on a mobile phone etc.
2. This web browser users an HTTPCLient
3. In order to create either an HTTP GET or an HTTP POST request
4. That will either POST (save) and order or GET (read an order) / create / login a user.
5. This is all done in JSON
We now need to secure this system in order to authenticate a user. Traditional applications made
use of cookies and session management in order to authentication users. When a user is
authenticated a session is created, the session ID is sent to the users machine with a cookie and
every time the users connects to the system he is authenticated with that session ID. Cookies are
not the world’s most secure things and our system cannot use this process regardless. Because we
have this disconnect (decoupled) client - server (api) model, we need to authenticate using JWT
(JSON WEB Tokens) this works as follows :

2.The token is sent


to the Client’s
browser as a
Cookie / Local
Storage and used
3.The token is attached for all future
to any HttpRequest requests. This
that is sent. token is created
with a strong
hashing algorithm
and cannot be
feaked

+TOKEN

1. The server
Generates a
JWT (hashed
4. Only the server that
into one long
created the token can
string
validate the token 😊😊
Using JWT to Provide Login Functionality :

We are no able to create users with our Sign Up functionality , we are successfully persisting our
users in the Mongo DB. Next we need to provide the necessary login functionality. We will start by
creating the login route in the backend\routes\user.js folder.

1. Lets start by adding the POST request that will be executed when a user access the
https://localhost:300/api/users/login route. We need to do the following in this HTTP POST
request:
1.1. We need to find the user that logged in and their email address, if we find a user , we would
like to compare the entered password with the password retrieved from the database.
These passwords are hashed – we thus need to use the brcyrpt.compare function that allows
us to compare hashed passwords. You can see the code for this below. You can add the
login HTTP POST request right beneath the Sign UP request:

We start our login Post


request here

We create a global variable to


use in all the code blocks that
will follow

We look for a user by looking


for the email address that
user entered in the login form

We state that Authentication


will fail if no user is found.

We compare the entered


You will find many console.log entries. It makes troubleshooting password and the stored
a lot easier. This allows us to log the data users enter , the data password if a user is found.
we compare to, the outcomes of conditions etc.

1.2. Once we found our user we and compared the passwords , we need to work with the results
of the comparison of the entered and stored passwords done with the bcrypt.compare
function. We want to return a message that the authentication failed if the passwords do
not match or we want to create a JWT token if the comparison did match and returned true
as the answer. We need to install the JWT token module if we want to use it. Stop your
sever by pressing Ctrl + C and install the JWT module with the following command.
1.3. Import the JWT module into your user.js file (backend\routes\users.js)

1.4. We are now ready to create the JWT token. Edit your code as indicated below:

router.post("/login",(req,res,next)=> {
// creating global user variable to use in different code blocks.
let fetchedUser;
//checks if we have user with a valid e-mail address
User.findOne({email:req.body.email})
.then(user=>{
console.log(user);
if(!user)
{
return res.status(401).json(
{
message: "Authentication Failed, try again "

});
}
// assigning retrieved user to global variable so we can use him later
fetchedUser= user;
//compares hashed passwords (alwasy the same hash with same input)
return bcrypt.compare(req.body.password,user.password)// compare returned
user password and password in db
})
.then(result=>{ After we have compared
console.log("2",result); the passwords, we enter a
then block in order to check
if(!result)
if the comparison returns
{
true or false. A false
return res.status(401).json(
comparison will output an
{
error. A true comparison
message: "Authentication Failure "
will create a JWT Token
});
}
//create JWT if user exists : JWT contains user e mail and user ID from
user object
const token = jwt.sign({email:fetchedUser.email,userId:fetchedUser._id},
'secret_this_should_be_longer_time_is',
{
expiresIn:'1h'
});
console.log(token);
res.status(200).json(
A JWT token is a hashed value to contains a given
{ set of data. In our case we are going to use the
token:token
user’s email, password and userID as well as a
}); We return our secret to create our token. You can read more
}) token using JSON about web tokens here: https://jwt.io/. We also
.catch(err =>{
want to set the time that token takes to expire in
console.log(err);
order to protect our app from CSRF attacks and
return res.status(401).json({
Session Jacking. We also log our token for
message:"Authentication Failure"
debugging purposes
});
})
Lastly we catch any errors and log them
so that we can see what they are. We
});
also return a message to indicate that
authentication failed.
module.exports= router;

Your entire users.js file should now look like this :

const express = require("express");


const router = express.Router();
const bcrypt = require("bcrypt")
const jwt = require("jsonwebtoken")
const User = require('../model/user')
router.post("/signup", (req, res, next) => {
bcrypt.hash(req.body.password,10)
.then(hash => {
const user = new User({
username:req.body.username,
email: req.body.email,
password: hash
});

console.log(req.body.password, req.body.email, req.body.username);


user .save()
.then(result => {
res.status(201).json({
message: "User created!",
result: result
});
})
.catch(err => {
res.status(500).json({
error: err
});
});
});
});

router.post("/login",(req,res,next)=> {
// creating global user variable to use in different code blocks.
let fetchedUser;
//checks if we have user with a valid e-mail address
User.findOne({email:req.body.email})
.then(user=>{
console.log(user);
if(!user)
{
return res.status(401).json(
{
message: "Authentication Failed, try again "

});
}
// assigning retrieved user to global variable so we can use him later
fetchedUser= user;
//compares hashed passwords (alwasy the same hash with same input)
return bcrypt.compare(req.body.password,user.password)// compare returned
user password and password in db
})
.then(result=>{
console.log("2",result);

if(!result)
{
return res.status(401).json(
{
message: "Authentication Failure "
});
}
//create JWT if user exists : JWT contains user e mail and user ID from
user object
const token = jwt.sign({email:fetchedUser.email,userId:fetchedUser._id},
'secret_this_should_be_longer_time_is',
{
expiresIn:'1h'
});
console.log(token);
res.status(200).json(

{
token:token
});
})
.catch(err =>{
console.log(err);
return res.status(401).json({
message:"Authentication Failure"
});
})

});

module.exports= router;

Using JWT to Authenticate Users on the Front end:

Now that we have our backend routes and HTTP REQUEST created, we need to hook this up to the
front end. We will follow the same process we followed when we created routes for our orders. We
will do the following:

1. We will Add login method to our Auth Service in the Auth.service.ts file.

2. We will then create an onLogin method in our Login component using our
login.component.ts file.

3. We will call the onLogin method in our HTML front end (login.component.html file)

1.1. Lets start by Adding the login method to the Auth.service.ts file:

Create the login method, Create a constant called Create the HTTP request that
this method will accept a authData(based on our will send our auth data to
user’s email, password model) that we will use to the correct URL –and log the
and username as send the information back to response.
parameters the server
1.2. Your completed Auth.service.ts file should now look like this:

import { Injectable } from '@angular/core';


import {HttpClient} from '@angular/common/http';
import { Router } from '@angular/router';
import { Subject } from 'rxjs';

import { AuthData } from './auth-data.model';

@Injectable({providedIn: 'root'})
export class AuthService
{

constructor(private http: HttpClient){}

createUser (email:string, password: string , username: string)


{

const authData: AuthData = {email:email, password:password,


username:username};

this.http.post('https://localhost:3000/api/user/signup', authData)
.subscribe(response =>{
console.log(response);
});
}

login(email:string, password:string, username:string)


{
const authData: AuthData = {email:email,
password:password,username:username };
this.http.post('https://localhost:3000/api/user/login',authData)
.subscribe(response => {
console.log(response);
})

}
1.3. We next need to use our service in our login.component.ts file in order to send the data
that the user has entered in our form to our server so that we can compare the
passwords and create the token (as previously discussed)

import { Component } from '@angular/core';


import {NgForm} from '@angular/forms';
import { AuthService } from '../auth-service';

@Component({
templateUrl: './login.component.html'
})

export class LoginComponent


{
enteredUserNameError = 'Please enter a user name in the correct form';
enteredEmailError = 'Please enter a correctly formatted e-mail addresss ';
enteredOrderError = 'Please enter an order of no more than 50 characters';
enteredPasswordError = 'Please enter a password that contains lower case,' +
'upper case letters and at least one number';

constructor (public authService:AuthService){} We make sure that we have


access to our auth service by
onLogin(form: NgForm) passing it into our constructor
{
if (form.invalid)
We make sure that our form is
{
valid before we process any
return;
data - we just return to the
}
form if it is not
this.authService.login(form.value.enteredEmail,
form.value.enteredPassword, form.value.enteredUsername) If we find that our form is valid
we pass the values entered
console.log(form.value) into our form into the login
} method from the Auth service
and send it to the server

1.4. If we restart our servers and create a user using the Sign Up Screen:
1.5. We should get the following if we inspect our application and look at the console :
1.6. We successfully created the user [email protected].
1.7. If we now go to the Login screen and login with [email protected]

1.8. We will see a successfully created token:

1.9. We can now use this token to Authenticate our users .


Using JWT to protect routes for create and Delete Orders :

Each user who signs up now has a token – we can now use this token to ensure that any user can
view our orders, but only logged in users can create or delete orders. We do this by protecting the
routes (HTTP REQUESTS) that will lead a user to the desired URL. We will need to create middle
ware for this. Middle ware will edit the post request before it is processed by our server and sent to
the database :

Create order Component

(Sends data to middle ware)

No Middle ware
yes
(Check that a
token exists)

Server
Server
Accepts Data and saves to
Throws Authorization 401 Error Database

We will need to create our own middle ware as we don’t have a module we could download to
check for a token for us:

1. Create a new folder in your backend folder and name it middleware. Once your folder is
done, create a new empty file and call it check-auth.ts .
2. We need the middle ware to check if a token is present in the http requests that the users
send our Node JS server. We need to add the following logic to the check-auth file:

1. Import
jsonwebtokens so
that we can work

We want
this process
to throw a
definite
error we
therefor
3. We then use the jwt.very function to verify that w
write our
have a valid web token – if we do , we log the message
logic into a
{token verified successfully , if not we catch the error
try and
with an Authentication faulire message
catch block

2. A JWT token is sent in the request header as a string (see


image below) we want to retrieve this token from the
header. You will see that the token comes straight after the
word bearer and a white space - we thus set our constant
token to : In the request header, find the authorization block
copy over the 2nd entry (1 because we start counting at 0)
behind the white space.

You will notice that we are exporting and entire response instead of storing it in a variable.
3. We can now use our middle ware to only allow a user to access a route (HTTP POST /
DELTE/GET request) if the user has a valid token. We will apply this to the orders.js routes
file.

4. We want to check that the user has a valid token before the request is processed in any
way. We thus edit our backend\routes\order.js file according to the following :
5.
6. const express = require("express");
7.
We import our middle ware
8. const router = express.Router();
into a constant called
9.
CheckAuth
10. const Order = require('../model/order')
11. const CheckAuth = require('../middleware/check-auth');
12.
13. router.post('',
14. //adding middle ware to check that a user is authenticated before they
can create posts.
15. CheckAuth, We execute the middle
16. (req,res,next)=> ware before we formulate
17. { the response for the create
18. const orders = new Order( order route.
19. {
20. userName : req.body.userName,
21. Email: req.body.Email,
22. PlacedOrder: req.body.PlacedOrder
23.
24. }
25. );
26. orders.save()
27. .then((createdOrder)=>
28. {
29. console.log(createdOrder);
30. res.status(201).json({
31. message: 'order successfully created',
32. orderID: createdOrder._id
33. });
34. console.log(orders);
35.
36. });
37.
38. });
39.
40. router.get('',(req,res,next)=> We do NOT check for a token
41. { on the GET request because
42. Order.find().then((documents)=>{ we want our users to browse
43. res.json( our orders
44. {
45. message: 'Orders retrieved from Server successfully',
46. orders:documents
47. });
48. });
49. });
50.
51. router.delete("/:id",
52. //Check if user has valid token using middle ware we created.
53. CheckAuth,
We do the same for the delete route
54. (req,res,next)=>
55. {
56. console.log(req.params.id);
57. Order.deleteOne({_id: req.params.id})
58. .then((result)=>
59. {
60. //console.log(result);
61. console.log("Order Deleted from DB");
62. res.status(200).json({message: "Order Deleted from Database"});
63.
64. });
65.
66. });
67.
68. module.exports = router;
69.
3. We should get the following error when we now try to create an order (remember to save
your changes in order for your server to restart)

4. Next we need to attach our token to any incoming request so that our CheckAuth
middleware can allow authenticated users to create and delete orders.

Adding tokens in order to Authenticate Requests:

The token is created when a user signs up and we can see the token from the auth service when a
user logs on. If we want to retrieve this token and send it along with our HTTP POST requests, we will
need to get it from the login request. If you look at the screenshot below, you will notice that the
token is generated by the auth-service.ts file on line 38. We will thus retrieve the token from this
file.

1. We log the server’s response to our http post request on line 38 , we can thus extract the
token from this response.
2. We will create a private property in our Auth Service. This property will hold our token which
we will retrieve from the body of our login request.

3. We do this in the login method. We create a constant called token ad we pull the actual
token out of our http request . We then store it in our constant. We lastly store our
extracted token in our property so that we can access it throughout our service.

We can configure our post request o


expect a token of type String

We can then extract and store the


token in our global property

You can learn more about SPA authentication here :https://medium.com/@jcbaey/authentication-


in-spa-reactjs-and-vuejs-the-right-way-e4a9ac5cd9a3
4. We will now need to create a method to move the token out of the Auth Service. We do this
by creating the getToken() method.

This method simply returns


our token to any other class
that calls it.

5. We next need to create an interceptor . Interceptors are angular functions that allows us to
intercept outgoing HTTP requests and manipulate them before they arrive at the server. We
will create our interceptor in our Auth folder:

6. Lets start populating our interceptor by adding the following logic:

Create a normal class that you


call AuthInterceptor. This class
will inherit from the
HttInterceptor Interface

This interface forces us to implement the


interceptor method that takes two arguments,
the request that we would like to intercept and
the handler that will allow us to handle the
intercepted request.
7. We will now code up our intercept method fully ( I have copied in the entire interceptor file
so that you can see the whole file to compare your code to)

We need
to We need to get access to our token
@Injectabl so that we can add it to our
e() so that request. We therefore inject our
we can auth service into our interceptor-
inject a we then use the getToken method
service from our Auth service to get our
into our retrieved token.
intercepto
r

We next clone our request and set the We lastly return the intercepted,
Authorization header to include our manipulated header
Token. We need to recreate the token ,
we thus append the Authorization and
Bearer strings to our token to math a
normal http POST header (see below)
8. We need to register our interceptor in the app.module file :

import { BrowserModule } from '@angular/platform-browser';


import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';


import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-
browser/animations';
import { FormsModule } from '@angular/forms';
import { MatInputModule ,
MatCardModule,
MatButtonModule,
MatExpansionModule} from '@angular/material';
import { OrderCreateComponent } from './orders/order-create/order-
create.component';
import { OrderPlacedComponent} from './orders/order-placed/order-
placed.component';

import {HttpClientModule, HTTP_INTERCEPTORS} from '@angular/common/http';


import { LoginComponent } from './Auth/login/login.component';
import { SignUpComponent } from './Auth/signup/signup.component';
import { AuthInterceptor } from './Auth/auth-interceptor';

@NgModule({
declarations: [
AppComponent,
OrderCreateComponent,
OrderPlacedComponent,
LoginComponent,
SignUpComponent

], We add a Java Script object with the


imports: [ provide property – we provide an identifier
BrowserModule, for HTTP_INTERCEPTORS and the class that
AppRoutingModule, we used as our Interceptors
BrowserAnimationsModule,
FormsModule, Make sure your IDE imports the necessary
MatInputModule, files. All out going request will now receive
MatCardModule, our interceptor
MatButtonModule,
MatExpansionModule,
HttpClientModule
],
providers: [{provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor}],
bootstrap: [AppComponent]
})
export class AppModule { }

9. We can now create a new user (we could use an old one but lets start fresh)

10. Our user is successfully created


11. We can now log in with Eddie:

12. Eddie and his token is logging in:


13. We can create an order:
14. And view our order:

15. If refresh the page and try and connect with a non-registered user:
16. You should get the following error which states that the user is not authorized to create
orders.

You can read more about HttpInterceptors here


:https://angular.io/api/common/http/HttpInterceptor

Adding HTML Sanitizers and HTML Entities to protect Against XSS and other attacks:
We have already used Regex to protect our input boxes from text characters that could be use to
launch attacks on our application. We will now round that off and implement HTMLEntities and
HTML sanitizers. HTML characters and Java Script commands can be used to attack your site with
Cross Site scripting. This does not mean that we should never accept HTML code as input. Some
website allows this and support it.

There are two ways to ensure that any html entered into your input boxes are sanitized.

1. Use String interpolation:

If we look at our e-mail input field from our order-create.component.html file , you will notice that
we output our error messages using string interpolation using the angular {{}} string interpolation
notation:
2. Angular will automatically sanitize any html provided using string interpolation. Let’s test
this. Let’s create a string variable output set that variable to what ever the user enters into
the order Textbox.

3. We will need to remove our regex Patter (pattern ="^[a-zA-Z0-9\s]+$") because this pattern
does not allow any characters that are used in HTML tags. We then create a new paragraph
tag <p> under the Entered order input field and use string interpolation to output our value.
4. If we enter <b> Strong Coffee </b> - exactly that will be shown as output. Angular will
automatically sanitize and not allow the HTML tags.
5. But what if we want to show the output in HTML how do we do this. We will need to change
our output variable slightly by placing it in a <div> tag. We will then make use of innerHTML
to instruct angular to output and render HTML

6. If I now enter <b> Strong Coffee </b> - The HTML tags are rendered.
7. This unfortunately means that we could enter potentially dangerous characters such as
IFRAMES used for click Jacking etc. So how to we safely render HTML output ?
Using the DOM Sanitizer to Sanitize HTML Output

1. We need to import the Dom Sanitizer:

2. We next need to add it to our constructor in order to have access to it:

3. Lastly we use the Dom Sanitizer to sanitize any html before we set our output property to
accept it. This will allow us to safely output and render HTML.
You can read more about DOM Sanitizer herehttps://angular.io/api/platform-
browser/DomSanitizer#sanitize, https://netbasal.com/angular-2-security-the-domsanitizer-service-
2202c83bd90

https://www.youtube.com/watch?v=6wD4V0rvlDI

Handling HTML entities:

One last thing that we need to discuss is HTML entities. HTML entities are used to display special
characters that are reserved for html. For example, the < tag. If I want to use that tag specially in an
order that is being displayed using html –you will encounter the following.
1. If we want to use a < symbol we need to use HTML Entities. The HTML entity for a < symbol
is &lt , there are many html entities that can be used:

Figure 8: Image Courtesy of Purple Code

2. You can find a full list of the available html entities here :
https://www.freeformatter.com/html-entities.html

3. Using innerHTML will also correctly decode, sanitize and allow HTML ENTITIES

<div [innerHtml]=

4. If we then use one of the entities along with [innerHtml] and our Sanitizer we will get the
following:
Error Handling

Displaying Basic Error Messages:

Error messages can be quite dangerous as they can inform attackers of weaknesses in your
application. It is important that we successfully handle errors and provide error messages that would
not give attackers unnecessary information. We will be creating a new interceptor that will
intercept our errors and allow us to display custom well worded error messages.

1. If you look back to the section that dealt with deleting orders you will remember that we
used the pipe() operator. This operator allowed us to work with an incoming data stream
(http request in our case). We will use the pipe operator to handle an HTTP Error Event.

2. The full interceptor is detailed below:

import { HttpInterceptor,HttpRequest, HttpHandler, HttpErrorResponse } from


'@angular/common/http';
import { Injectable } from '@angular/core';
import { catchError } from 'rxjs/operators';
We intercept the
import { throwError } from 'rxjs';
HttpRequest and
we use the http
handler to handle
@Injectable()
the incoming http
export class ErrorInterceptor implements HttpInterceptor
{
request.

constructor(){}
We then use the pipe
intercept(req: HttpRequest<any>, next: HttpHandler) function to apply the
{ catchError operator to
return next.handle(req).pipe( the request. We are
retrieving an error of
type HttpErrorResponse
from the request. We
then log the error()
catchError((error: HttpErrorResponse)=>{
console.log(error);
alert(error.error.message);
return throwError(error); We then pop up an alert box containing
the error we rerieve. You will notice that
}) we use error.error.message. that is
); because there are two error entries in the
} request ( see image below)
}

Error.error.message

3. We can now register our interceptor:

import { BrowserModule } from '@angular/platform-browser';


import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';


import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-
browser/animations';
import { FormsModule } from '@angular/forms';
import { MatInputModule ,
MatCardModule,
MatButtonModule,
MatExpansionModule} from '@angular/material';
import { OrderCreateComponent } from './orders/order-create/order-
create.component';
import { OrderPlacedComponent} from './orders/order-placed/order-
placed.component';

import {HttpClientModule, HTTP_INTERCEPTORS} from '@angular/common/http';


import { LoginComponent } from './Auth/login/login.component';
import { SignUpComponent } from './Auth/signup/signup.component';
import { AuthInterceptor } from './Auth/auth-interceptor';
import { ErrorInterceptor } from './error.interceptor';

@NgModule({
declarations: [
AppComponent,
OrderCreateComponent,
OrderPlacedComponent,
LoginComponent,
SignUpComponent We import the interceptor
in the exact same manner
], we used to import the Auth
imports: [ interceptor. Make sure
BrowserModule, that your imports are
AppRoutingModule, automatically added.
BrowserAnimationsModule,
FormsModule,
MatInputModule,
MatCardModule,
MatButtonModule,
MatExpansionModule,
HttpClientModule
],
providers: [{provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor,
multi:true},
{provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi:true}
],
bootstrap: [AppComponent]
})
export class AppModule { }

4. If we now try and log on with a user that does not exist – we will get a message that displays
the error to us :
Formatting and Displaying custom error messages:

We are now able to display our error messages , unfortunately these messages are formatted poorly
and display only system messages. We would like to provide a predefined error message as well as
properly format our error messages. We can once again use some of the Angular material features
to enhance the appearance of our error messages.

1. We need to import the MatDialogModule into our app.module.ts file:

2. We also need to add our module to the imports array ( Just as we did with all the other
modules that we used:
3. Your full app.module.ts file will now look like this:
4. import { BrowserModule } from '@angular/platform-browser';
5. import { NgModule } from '@angular/core';
6.
7. import { AppRoutingModule } from './app-routing.module';
8. import { AppComponent } from './app.component';
9. import { BrowserAnimationsModule } from '@angular/platform-
browser/animations';
10. import { FormsModule } from '@angular/forms';
11. import { MatInputModule ,
12. MatCardModule,
13. MatButtonModule,
14. MatExpansionModule,
15. MatDialogModule} from '@angular/material';
16. import { OrderCreateComponent } from './orders/order-create/order-
create.component';
17. import { OrderPlacedComponent} from './orders/order-placed/order-
placed.component';
18.
19. import {HttpClientModule, HTTP_INTERCEPTORS} from
'@angular/common/http';
20.
21. import { LoginComponent } from './Auth/login/login.component';
22. import {ErrorComponent} from './error/error.component';
23. import { SignUpComponent } from './Auth/signup/signup.component';
24. import { AuthInterceptor } from './Auth/auth-interceptor';
25. import { ErrorInterceptor } from './error.interceptor';
26.
27. @NgModule({
28. declarations: [
29. AppComponent,
30. OrderCreateComponent,
31. OrderPlacedComponent,
32. LoginComponent,
33. SignUpComponent,
34. ErrorComponent
35. ],
36. imports: [
37. BrowserModule,
38. AppRoutingModule,
39. BrowserAnimationsModule,
40. FormsModule,
41. MatInputModule,
42. MatCardModule,
43. MatButtonModule,
44. MatExpansionModule,
45. HttpClientModule,
46. MatDialogModule
47. ],
48. providers: [{provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor,
multi:true},
49. {provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor,
multi:true}
50. ],
51. bootstrap: [AppComponent],
52. entryComponents: [ErrorComponent]
53. })
54. export class AppModule { }
55.

5. We are now ready to start styling our errors better and to provide a custom error message
for any errors that do not output a system defined message. We will need to create a new
component for this : You can go ahead and crate the error folder which will contain our
error.component.ts file.

6. We can now go ahead and create our err.component.ts file.


7. The errror.componen.ts file will contain the following :

We will then output


our message in
HTML using string
interpolation

We will simply
create a property
that contains our
message

8. We will need to create the html file to use for our string interpolation - go ahead an create
error.component.html ( the same file that we are calling into our component as the
templateUrl)

9. We will simply display a header message informing us that an error occurred. We will then
use string interpolation to retrieve the string stored in our error message variable from our
error.component.ts file.
10. We now need to register our component so that Angular is aware of it. You will notice that
we did not pass the selector value into our component decorator as we did for our other
components. If you look at the order-create.component.ts file’s Component decorator – you
will see that it looks like the image below:

11. The error.component.ts file has the following in it’s decorator:

12. This means that we will need to add this component to our app.module.ts file in a different
way. We do this by using the entryComponents array. This will make our component
available throughout our application.
13. Your entire app.module.ts file should now look like this:

import { BrowserModule } from '@angular/platform-browser';


import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';


import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-
browser/animations';
import { FormsModule } from '@angular/forms';
import { MatInputModule ,
MatCardModule,
MatButtonModule,
MatExpansionModule,
MatDialogModule} from '@angular/material';
import { OrderCreateComponent } from './orders/order-create/order-
create.component';
import { OrderPlacedComponent} from './orders/order-placed/order-
placed.component';

import {HttpClientModule, HTTP_INTERCEPTORS} from '@angular/common/http';

import { LoginComponent } from './Auth/login/login.component';


import {ErrorComponent} from './error/error.component';
import { SignUpComponent } from './Auth/signup/signup.component';
import { AuthInterceptor } from './Auth/auth-interceptor';
import { ErrorInterceptor } from './error.interceptor';

@NgModule({
declarations: [
AppComponent,
OrderCreateComponent,
OrderPlacedComponent,
LoginComponent,
SignUpComponent,
ErrorComponent
],
imports: [
BrowserModule,
AppRoutingModule,
BrowserAnimationsModule,
FormsModule,
MatInputModule,
MatCardModule,
MatButtonModule,
MatExpansionModule,
HttpClientModule,
MatDialogModule
],
providers: [{provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor,
multi:true},
{provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi:true}
],
bootstrap: [AppComponent],
entryComponents: [ErrorComponent]
})
export class AppModule { }

14. Now that we have registered the component, we can use it in our interceptor to make use of
the angular materials development dialog box. We can currently only display an error that
states an Unknown error has occurred. We want to make use of the built in errors and
display them in the Angular Material Design Mat Dialog box ( you can read more on it here:
https://material.angular.io/components/dialog/overview)

We create a variable
containing our default
error message

We then use an if statement to


check if an error message is
present in our http Request. If an
error message is present, we
overwrite the data in the error
message variable

We next need to send this data to our


error component. We send the data to it
as an object when we open the
component
15. We now need to send this data back to your error.component.ts file so that we can display
this data using the properly formatted dialog box and more precise error. We do this as
follows:

We need to inject the data coming


from our interceptor into our
error.component. We need to
import the Inject module for @
angular/core and the
MAT_DIALOG_DATA module from
angular material

You will notice that Inject our data differently than the services
that we have been injecting using @Injectable for our other
components. WE need to use @Inject because we use no
selector for this component. We inject the data as an object –
we create the public data property that holds the message sent
to us by the interceptor. We can only do this because we are
also injecting the MAT-DIALOG-DATA module.

16. We can now change our HTML to access the data being sent from our interceptor to our
component.
17. If we now log on with an incorrect user name and password – we get an authentication
error:

https://medium.com/@aleixsuau/error-handling-angular-859d529fa53a
Leveraging Libraries to protect our Application

NPM Audit :

We also need to protect our application from a wide range of attacks , it would take very long to
manually protect our site from all threats – we can however make use built in libraries. One such
library is npm audit. It comes with the new version of npm . You will need to run npm install npm – g
in order to update your version of npm.

You can read more about npm audit here : https://blog.npmjs.org/post/173719309445/npm-audit-


identify-and-fix-insecure

1. You can run npm audit once you have update your current version of npm:

2. You will receive the following security report after around 2 minutes: This is lengthy report that
finds our vulnerabilities and recommends packages that you can install to resolve your
vulnerabilities.
3. You will also receive the following output: We can run npm audit ix to solve 13 of our
vulnerabilities.

4. We can no run npm audit fix

5. Wait for the process to complete- you will now have a much more secure application.
Express Brute to Protect from Brute Force Attacks:

Lastly we need to protect our login form from Brute force Attacks, we can do this by importing the
Express Brute middleware . We will first need to install it.

1. Run npm install express-brute.

2. We need to protect our /login HTTP POST request. Navigate to the backend\routes\user.js
folder and Import express-brute into a constant named Express Brute. We will also import
the memory store as we are not in a production environment.

3. We can now implement he express brute middle ware to prevent brute-force attacks aimed
at out /login route.

You can learn more about express brute here : https://www.npmjs.com/package/express-brute


Annexures: Full Project Files:

Backend\middleware\check-auth.js

const jwt = require('jsonwebtoken');


//function executed on incoming request.
module.exports=(req,res,next)=>
{
try{
const token = req.headers.authorization.split(" ")[1];
jwt.verify(token,"secret_this_should_be_longer_time_is")
console.log("token Verified successfully");
next();

}
catch(error)
{
res.status(401).json({
message:"middle ware Auth Failed- no valid token set"
});
}

};

Backend\model\order.js

const mongoose = require('mongoose');

const orderSchema = mongoose.Schema(


{
userName: {type: String , required:true},
Email:{type: String , required:true},
PlacedOrder:{type: String , required:true}
}

);

module.exports =mongoose.model('Order', orderSchema);


Backend\model\user.js

const mongoose = require('mongoose');


const uniqueValidator = require('mongoose-unique-validator')

const userSchema = mongoose.Schema(


{
username: {type: String , required:true},
email:{type: String , required:true , unique:true},
password:{type: String , required:true}
}

);

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

Backend\routes\order.js

const express = require("express");


const router = express.Router();
const Order = require('../model/order')
const CheckAuth = require('../middleware/check-auth');

router.post('',
//adding middle ware to check that a user is authenticated before they can
create posts.
CheckAuth,
(req,res,next)=>
{
const orders = new Order(
{
userName : req.body.userName,
Email: req.body.Email,
PlacedOrder: req.body.PlacedOrder

}
);
orders.save()
.then((createdOrder)=>
{
console.log(createdOrder);
res.status(201).json({
message: 'order successfully created',
orderID: createdOrder._id
});
console.log(orders);

});

});

router.get('',(req,res,next)=>
{
Order.find().then((documents)=>{
res.json(
{
message: 'Orders retrieved from Server successfully',
orders:documents
});
});
});

router.delete("/:id",
//Check if user has valid token using middle ware we created.
CheckAuth,
(req,res,next)=>
{
console.log(req.params.id);
Order.deleteOne({_id: req.params.id})
.then((result)=>
{
//console.log(result);
console.log("Order Deleted from DB");
res.status(200).json({message: "Order Deleted from Database"});

});

});

module.exports = router;
Backend\routes\users.js

onst express = require("express");


const router = express.Router();
const bcrypt = require("bcrypt")
const jwt = require("jsonwebtoken")
const User = require('../model/user')
const ExpressBrute = require('express-brute');
const store = new ExpressBrute.MemoryStore(); // stores state locally, don't
use this in production
const bruteforce = new ExpressBrute(store);

//const bruteforce = new ExpressBrute(store);

router.post("/signup", (req, res, next) => {


bcrypt.hash(req.body.password,10)
.then(hash => {
const user = new User({
username:req.body.username,
email: req.body.email,
password: hash
});

console.log(req.body.password, req.body.email, req.body.username);


user .save()
.then(result => {
res.status(201).json({
message: "User created!",
result: result
});
})
.catch(err => {
res.status(500).json({
error: err
});
});
});
});

router.post("/login",
bruteforce.prevent,
(req,res,next)=> {
// creating global user variable to use in different code blocks.
let fetchedUser;
//checks if we have user with a valid e-mail address
User.findOne({email:req.body.email})
.then(user=>{
console.log(user);
if(!user)
{
return res.status(401).json(
{
message: "Authentication Failed, try again "

});
}
// assigning retrieved user to global variable so we can use him later
fetchedUser= user;
//compares hashed passwords (alwasy the same hash with same input)
return bcrypt.compare(req.body.password,user.password)// compare returned
user password and password in db
})
.then(result=>{
console.log("2",result);

if(!result)
{
return res.status(401).json(
{
message: "Authentication Failure "
});
}
//create JWT if user exists : JWT contains user e mail and user ID from
user object
const token = jwt.sign({email:fetchedUser.email,userId:fetchedUser._id},
'secret_this_should_be_longer_time_is',
{
expiresIn:'1h'
});
console.log(token);
res.status(200).json(

{
token:token
});
})
.catch(err =>{
console.log(err);
return res.status(401).json({
message:"Authentication Failure"
});
})

});
module.exports= router;
Backend\app.js

const express = require('express');


const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const fs = require('fs');
const orderRoutes = require("./routes/orders");
const userRoutes = require("./routes/user");

const cert = fs.readFileSync('keys/certificate.pem');


const options = {
server: { sslCA: cert }};

const app = express();

mongoose.connect("mongodb+srv://SamAdmin:D47fLwhCiLGrYYxM@cluster0-
glieu.mongodb.net/order-system?retryWrites=true")
.then(()=>
{
console.log("connected to DB successfully ! YAY")
})
.catch(()=>
{
console.log('Apparently not !!!')
},options);

app.use(bodyParser.json())

app.use((reg,res,next)=>
{
res.setHeader("Access-Control-Allow-Origin", '*');
res.setHeader("Access-Control-Allow-Headers",
"Origin ,X-Requested-With,Content-Type,Accept,Authorization"
);
res.setHeader("Access-Control-Allow-Methods",
"*");
next();

});

app.use("/api/orders",orderRoutes)
app.use("/api/user",userRoutes)
module.exports = app;
Auth\login\ogin.component.ts

import { Component } from '@angular/core';


import {NgForm} from '@angular/forms';
import { AuthService } from '../auth-service';

@Component({
templateUrl: './login.component.html'
})

export class LoginComponent


{
enteredUserNameError = 'Please enter a user name in the correct form';
enteredEmailError = 'Please enter a correctly formatted e-mail addresss ';
enteredOrderError = 'Please enter an order of no more than 50 characters';
enteredPasswordError = 'Please enter a password that contains lower case,' +
'upper case letters and at least one number';

constructor (public authService:AuthService){}

onLogin(form: NgForm)
{
if (form.invalid)
{
return;
}

this.authService.login(form.value.enteredEmail,
form.value.enteredPassword, form.value.enteredUsername)

console.log(form.value)
}

}
Auth\login\login.component.html

<p>Please Log in </p>

<mat-card>

<form (submit)="onLogin(loginForm)" class = "login" name = "login"


#loginForm="ngForm" >

<br>
<mat-form-field>
<input matInput type ="email" pattern ="^[\w-\.]+@([\w-]+\.)+[\w-
]{2,4}$"
ngModel name ="enteredEmail"
placeholder="Email Adrress" required
#enteredEmail ="ngModel"/>
<mat-error *ngIf="enteredEmail.invalid">{{enteredEmailError}}</mat-
error>
</mat-form-field>
<br>

<mat-form-field>
<input matInput type ="password" pattern ="^([a-zA-Z0-9@*#]{8,15})$"
ngModel name ="enteredPassword"
placeholder="Password" required
#enteredPassword ="ngModel"/>
<mat-error *ngIf="enteredPassword.invalid">{{enteredPasswordError}}</mat-
error>
</mat-form-field>
<br>
<button mat-raised-button type = "submit" >Login</button>
</form>
</mat-card>
<hr>
Auth\singup\singnup.component.html:

<p>Please Sign Up</p>


<mat-card>
<form (submit)=”onSignup(signupForm)” class = “login” name = “login”
#signupForm=”ngForm” >
<mat-form-field>
<input matInput type =”text” ngModel name=”enteredUserName”
placeholder =”User Name”
required
minlength=”8”
pattern =”^[a-zA-Z0-9\s_-]+$”
#enteredUserName =”ngModel”
sanitize/>
<mat-error
*ngIf=”enteredUserName.invalid”>{{enteredUserNameError}}</mat-error>
</mat-form-field >
<br>
<mat-form-field>
<input matInput type =”email”
ng-bind-html
pattern =”^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$”
ngModel name =”enteredEmail”
placeholder=”Email Adrress” required
#enteredEmail =”ngModel”/>
<mat-error *ngIf=”enteredEmail.invalid”>{{enteredEmailError}}</mat-
error>
</mat-form-field>
<br>
<mat-form-field>
<input matInput type =”password”
ng-bind-html
pattern =”^([a-zA-Z0-9@*#]{8,15})$”
ngModel name =”enteredPassword”
placeholder=”Password” required
#enteredPassword =”ngModel”/>
<mat-error *ngIf=”enteredPassword.invalid”>{{enteredPasswordError}}</mat-
error>
</mat-form-field>
<br>
<button mat-raised-button type = “submit” >Sign Up</button>
</form>
</mat-card>
<hr>
Auth\signup\singup.component.ts

import { Component } from '@angular/core';


import {NgForm} from '@angular/forms';
import { AuthService } from '../auth-service';

@Component({
templateUrl: '../signup/signup.component.html'
})

export class SignUpComponent


{
enteredUserNameError = 'Please enter a user name in the correct form';
enteredEmailError = 'Please enter a correctly formatted e-mail addresss ';
enteredOrderError = 'Please enter an order of no more than 50 characters';
enteredPasswordError = 'Please enter a password that contains lower case,' +
'upper case letters and at least one number';

constructor(public authService: AuthService) {}

onSignup(form: NgForm)
{

if (form.invalid) {
return;
}

this.authService.createUser(form.value.enteredEmail,
form.value.enteredPassword, form.value.enteredUserName);

console.log(form.value);
}
}
Auth\auth-data.model.ts
export interface AuthData

{
username: string;
email: string;
password: string;
}

Auth\auth.interceptor.ts

import { HttpInterceptor,HttpRequest, HttpHandler } from


'@angular/common/http';
import { Injectable } from '@angular/core';
import { AuthService } from './auth-service';

@Injectable()
export class AuthInterceptor implements HttpInterceptor
{

constructor(private authService:AuthService){}

intercept(req: HttpRequest<any>, next: HttpHandler)


{
const authToken = this.authService.getToken();
const authRequest = req.clone({headers: req.headers.set("Authorization",
"Bearer " + authToken)
});
return next.handle(authRequest);
}
}
Auth\auth.service.ts

import { Injectable } from '@angular/core';


import {HttpClient} from '@angular/common/http';
import { Router } from '@angular/router';
import { Subject } from 'rxjs';

import { AuthData } from './auth-data.model';

@Injectable({providedIn: 'root'})
export class AuthService
{
private token : string;

constructor(private http: HttpClient){}

createUser (email:string, password: string , username: string)


{

const authData: AuthData = {email:email, password:password,


username:username};

this.http.post('https://localhost:3000/api/user/signup', authData)
.subscribe(response =>{
console.log(response);
});
}

login(email: string, password:string, username: string)


{
const authData: AuthData = {email:email,
password:password,username:username };
this.http.post<{token: string
}>('https://localhost:3000/api/user/login',authData)
.subscribe(response => {
const token = response.token;
this.token = token;
console.log(response);
});
}
getToken()
{
return this.token;
}

Error\error.component.ts

import {Component, Inject} from "@angular/core";


import {MAT_DIALOG_DATA} from "@angular/material";

@Component({

templateUrl: './error.component.html'

})
export class ErrorComponent
{
constructor(@Inject (MAT_DIALOG_DATA) public data: {message:string}){}

Error\error.component.html

<h1>An Error has Occured </h1>


<p>{{data.message}}</p>
\orders\order-create\order.create.component.ts

import { Component, Sanitizer, SecurityContext } from '@angular/core';


import { NgForm } from '@angular/forms';
import { OrdersService } from '../order.service';
import { ActivatedRoute } from '@angular/router';
import { DomSanitizer } from '@angular/platform-browser';

@Component({
selector:'app-order-create',
templateUrl:'./order-create.component.html',
styleUrls:['./order-create.component.css']
})

export class OrderCreateComponent


{
enteredUserNameError = 'Please enter a user name in the correct form';
enteredEmailError = 'Please enter a correctly formatted e-mail addresss ';
enteredOrderError = '<b>Please enter an order of no more than 50
characters</b>';
output:string;

constructor(public orderService:OrdersService, public route : ActivatedRoute


,
protected sanitizer: DomSanitizer){}
onAddOrder(Orderform: NgForm)
{

if (Orderform.invalid)
{
return;
}

this.orderService.addOrders(Orderform.value.enteredUserName,
Orderform.value.enteredEmail
, Orderform.value.enteredOrder);
this.output = (this.sanitizer.sanitize(SecurityContext.HTML,
Orderform.value.enteredOrder) );
Orderform.resetForm();

}
\orders\order-create\order.create.component.html

<p>Create your order here please</p>


<mat-card>
<form class = "login" name = "login" (submit)="onAddOrder(postOrder)"
#postOrder="ngForm" >
<mat-form-field>
<input matInput type ="text" ngModel name="enteredUserName"
placeholder ="User Name"
required
minlength="8"
pattern ="^[a-zA-Z0-9\s_-]+$"
#enteredUserName ="ngModel"/>
<mat-error
*ngIf="enteredUserName.invalid">{{enteredUserNameError}}</mat-error>
</mat-form-field >
<br>
<mat-form-field>
<input matInput type ="email" pattern ="^[\w-\.]+@([\w-]+\.)+[\w-
]{2,4}$"
ngModel name ="enteredEmail"
placeholder="Email Adrress" required
#enteredEmail ="ngModel"/>
<mat-error *ngIf="enteredEmail.invalid">{{enteredEmailError}}</mat-
error>
</mat-form-field>
<br>
<mat-form-field>
<textarea matInput ngModel name = "enteredOrder"
ng-bind-html
required
placeholder="Order Details"
maxlength="50"
#enteredOrder ="ngModel"></textarea>
<mat-error *ngIf="enteredOrder.invalid">{{enteredOrderError}}</mat-error>
</mat-form-field >
<br>
<p> You entered the following order</p>
<div [innerHtml]= 'output'></div>

<br>
<button mat-raised-button type = "submit" >Order Now</button>
</form>

</mat-card>
<hr>
\orders\order-placed\order-placed.component.ts

import { Component , OnInit, OnDestroy} from '@angular/core';


import { Order } from '../order.model';
import { OrdersService } from '../order.service';
import {Subscription} from 'rxjs';

@Component({
selector: 'app-order-placed',
templateUrl: './order-placed.component.html',
styleUrls: ['./order-placed.component.css']
})

export class OrderPlacedComponent implements OnInit , OnDestroy


{

orders: Order [] = [];

constructor( public orderService: OrdersService){}


private ordersSubscription: Subscription ;

ngOnInit() {

this.orderService.getOrders();
this.ordersSubscription = this.orderService.getPostUpdateListener()
.subscribe((orders: Order[]) =>
{
this.orders = orders;
});
}

onDelete(orderID: string )
{
this.orderService.deleteOrder(orderID);
}

ngOnDestroy()
{
this.ordersSubscription.unsubscribe();
}

}
\orders\order-placed\order-placed.component.html

<mat-accordion multi = "true" *ngIf= "orders.length >0">


<mat-expansion-panel *ngFor=" let order of orders">
<mat-expansion-panel-header
aria-placeholder="User Name"
>
{{order.userName}}

</mat-expansion-panel-header>
{{order.Email}}

<br>
{{order.PlacedOrder}}
<mat-action-row>
<button mat-button color="primary">edit </button>
<button mat-button color="warn" (click)="onDelete(order.id)">delete
</button>
<button mat-button color ="primary"> save post </button>
</mat-action-row>

</mat-expansion-panel>

</mat-accordion>
<p *ngIf="orders.length ==0">No orders created yet</p>

\order\order.model.ts:

export interface Order


{
id: string;
userName: string;
Email: string;
PlacedOrder: string;

}
\order\order.service.ts:

import { Order} from './order.model';


import { Injectable } from '@angular/core';
import {Subject} from 'rxjs';
import {HttpClient} from '@angular/common/http';
import {map} from 'rxjs/operators';

@Injectable({providedIn: 'root'})
export class OrdersService
{
private orders: Order [] = [] ;
private updatedOrders = new Subject<Order[]>();

constructor(private http: HttpClient){}

getOrders()
{
this.http.get<{message: string, orders:
any}>('https://localhost:3000/api/orders')
.pipe(map((orderData)=>
{
return orderData.orders.map(order=>{
return {
userName: order.userName,
Email: order.Email,
PlacedOrder: order.PlacedOrder,
id: order._id
};
});
}))
.subscribe((changedOrders)=>
{
this.orders = changedOrders;
this.updatedOrders.next([...this.orders]);

});
}

getPostUpdateListener()
{
return this.updatedOrders.asObservable();
}

addOrders(userName: string , Email: string , PlacedOrder: string )


{
const order: Order = {id :null,userName : userName , Email: Email,
PlacedOrder: PlacedOrder};
this.http.post<{message: string, orderId: string}
>('https://localhost:3000/api/orders',order)
.subscribe((responseOrderData)=>{
console.log(responseOrderData.message);
const id = responseOrderData.orderId;
order.id= id;
this.orders.push(order);
this.updatedOrders.next([...this.orders]);
});

deleteOrder(orderID: string)
{
this.http.delete('https://localhost:3000/api/orders/' + orderID)
.subscribe(()=>
{
const updatedOrdersDel = this.orders.filter(order =>order.id!== orderID);
this.orders= updatedOrdersDel;
this.updatedOrders.next([...this.orders]);
console.log('Order Deleted');

});
}

savefile()
{

}
app.routing.module.ts

import { NgModule } from '@angular/core';


import { Routes, RouterModule } from '@angular/router';
import { OrderCreateComponent } from './orders/order-create/order-
create.component';
import { OrderPlacedComponent } from './orders/order-placed/order-
placed.component';
import { LoginComponent } from './Auth/login/login.component';
import { SignUpComponent } from './Auth/signup/signup.component';

const routes: Routes = [


{path:'', component:OrderPlacedComponent},
{path:'create', component:OrderCreateComponent},
{path:'edit/:postId', component:OrderCreateComponent},
{path:'login', component: LoginComponent},
{path:'signup', component: SignUpComponent}

];

@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }

app.component.css

main{
margin-top: 1 rem;
width: 60%;
margin:auto;
text-align: center;

}
App.component.html:

<!--The content below is only a placeholder and can be replaced.-->


<main>

<div style="text-align:center">
<h1>
Order System Inc
</h1>
<nav>
<button mat-button color="primary" [routerLink]="['/create']"
routerLinkActive="router-link-active" > Create Order </button>
<button mat-button color="primary" [routerLink]="['/create']"
routerLinkActive="router-link-active" > Edit Order </button>
<button mat-button color="primary" [routerLink]="['/']"
routerLinkActive="router-link-active" > List Orders </button>
<button mat-button color="primary" [routerLink]="['/login']"
routerLinkActive="router-link-active" > Log In </button>
<button mat-button color="primary" [routerLink]="['/signup']"
routerLinkActive="router-link-active" > Sign Up</button>
</nav>
<br>
<router-outlet></router-outlet>

</div>
</main>
App.module.ts:

import { BrowserModule } from '@angular/platform-browser';


import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';


import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-
browser/animations';
import { FormsModule } from '@angular/forms';
import { MatInputModule ,
MatCardModule,
MatButtonModule,
MatExpansionModule,
MatDialogModule} from '@angular/material';
import { OrderCreateComponent } from './orders/order-create/order-
create.component';
import { OrderPlacedComponent} from './orders/order-placed/order-
placed.component';

import {HttpClientModule, HTTP_INTERCEPTORS} from '@angular/common/http';

import { LoginComponent } from './Auth/login/login.component';


import {ErrorComponent} from './error/error.component';
import { SignUpComponent } from './Auth/signup/signup.component';
import { AuthInterceptor } from './Auth/auth-interceptor';
import { ErrorInterceptor } from './error.interceptor';

@NgModule({
declarations: [
AppComponent,
OrderCreateComponent,
OrderPlacedComponent,
LoginComponent,
SignUpComponent,
ErrorComponent
],
imports: [
BrowserModule,
AppRoutingModule,
BrowserAnimationsModule,
FormsModule,
MatInputModule,
MatCardModule,
MatButtonModule,
MatExpansionModule,
HttpClientModule,
MatDialogModule
],
providers: [{provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor,
multi:true},
{provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi:true}
],
bootstrap: [AppComponent],
entryComponents: [ErrorComponent]
})
export class AppModule { }

error.interceptor.ts
import { HttpInterceptor,HttpRequest, HttpHandler, HttpErrorResponse } from
'@angular/common/http';
import { Injectable } from '@angular/core';
import { catchError } from 'rxjs/operators';
import { throwError } from 'rxjs';
import { MatDialog } from '@angular/material';
import {ErrorComponent} from './error/error.component';

@Injectable()
export class ErrorInterceptor implements HttpInterceptor
{

constructor(private dialog: MatDialog){}

intercept(req: HttpRequest<any>, next: HttpHandler)


{
return next.handle(req).pipe(

catchError((error: HttpErrorResponse)=>{
let errorMessage = "An Unknown Error has occured ";
if (error.error.message)
{
errorMessage = error.error.message;

}
console.log(error);
this.dialog.open(ErrorComponent,{data:{message:errorMessage}});
return throwError(error);

})
);
}
}
Server.js

const app = require("./backend/app");


const debug = require("debug")("node-angular");
const http = require("https");
const fs = require('fs');

const normalizePort = val => {


var port = parseInt(val, 10);

if (isNaN(port)) {
// named pipe
return val;
}

if (port >= 0) {
// port number
return port;
}

return false;
};

const onError = error => {


if (error.syscall !== "listen") {
throw error;
}
const bind = typeof port === "string" ? "pipe " + port : "port " + port;
switch (error.code) {
case "EACCES":
console.error(bind + " requires elevated privileges");
process.exit(1);
break;
case "EADDRINUSE":
console.error(bind + " is already in use");
process.exit(1);
break;
default:
throw error;
}
};

const onListening = () => {


const addr = server.address();
const bind = typeof port === "string" ? "pipe " + port : "port " + port;
debug("Listening on " + bind);
};
const port = normalizePort(process.env.PORT || "3000");
app.set("port", port);

const server = http.createServer(


{
key: fs.readFileSync('keys/privatekey.pem'),
cert: fs.readFileSync('keys/certificate.pem')
},app);
server.on("error", onError);
server.on("listening", onListening);
server.listen(port);

You might also like