Hello, dear friend, you can consult us at any time if you have any questions, add WeChat: daixieit

SENG365 Lab 2

Persisting Data, Postman Testing, and Structuring Applications in Node with TypeScript

8th March 2023

Purpose of this Lab

Last week we had an introductory look at using JavaScript, Node, and Express to create a small micro-blogging API. This week’s lab expands on these concepts in the domain of a chat app bringing in many new features and technologies. Due to the scope of this lab it is expected to take more than one lab session to complete, however once completed you should have the necessary skills and knowledge to begin working on your first assignment.

This lab is broken up into several segments. Firstly we will look into data persistence using MySQL. This is followed by the largest and most important section where we will create the chat app API, making use of proper application structure, TypeScript, validation, and a few other Node best practices. This will be followed by a look at how to test the API using Postman. Finishing with a small introduction to API specifications, and leaving you to complete the rest of the application to the introduced specification.

1 Persisting Data with MySQL

1.1 Conceptual Modelling

In the chat application, we will have multiple users that can talk to each other in conversations. Each conversation can contain multiple messages.  Each conversation must have at least two users. There is no upper limit on the number of users that can participate in a conversation. Figure 1shows the Entity Relationship Diagram1 (ERD) for the chat application

1.2 Connecting to the MySQL Server

Each student enrolled in SENG365 has a user account on the course’s MySQL server. You can access the database both on and off campus. The connection details are as follows:

•  Hostname: db2.csse.canterbury.ac.nz

•  Username: your student user code (e.g. abc123)

•  Password: your student ID (e.g. 12345678)

You can manage your database using phpMyAdmin. To access the control panel go to https://dbadmin.csse. canterbury.ac.nz/. Note: to access phpMyAdmin you will go through two authentication steps; The first will be

Figure 1: Entity relationship diagram for the chat app.

before the page loads and requires your UC username and password, the next will be when trying to log in through the admin portal, here is where you will input your user code and id as mentioned above.

Once you have logged into phpMyAdmin, you should be able to the databases starting with your user code for example abc123_main.

From here it is suggested you create a new database specifically for this lab, e.g.  abc123_s365_lab2 as seen in Figure 2.

Figure 2: Example creation of database for this lab.

1.3 Creating Tables

Now that we have access to our database, we will create a database using the lab2_init.sql script 2. This database will have the tables and fields shown in Figure 3. Look through the SQL script for more detailed information on the foreign key constraints.

We can run the entire SQL script on our database by opening a terminal (on your local machine) and running the following command.

mysql -hdb2 .csse .canterbury .ac .nz -uabc123 -Dabc123_s365_lab2 -p<lab2_ init .sql

Note that you will need to make sure you update the user code to your own, and run the terminal from the same directory as the lab2_init.sql file.

Alternatively, in case you don’t have mysql installed in your home computer (all labs computers have it installed), you can open a SQL terminal though phpMyAdmin (make sure you’ve selected the database for this lab), paste the given script content and run it from there. See an example of what this should3 look like in Figure 4.

Finally make sure you confirm the operation through the pop-up, making sure that everything looks correct first.

Figure 3: Database schema for chat app, derived from the ER diagram above.

Figure 4: Example DBAdmin executing SQL script.

1.4 Reading Database Parameters from Environment Variables

We do not want to be putting our confidential username and password into our codebase (especially if we put that code under version control!). Therefore we need a way to inject the necessary details into our application at runtime. This is where environment variables come to the rescue.

To do this we will make use of the dotenv4module later in the lab when we get into actually coding the application. This works by including a .env file at the root of our project with key=value pairs.

Notes:

•  If you are working from home please follow the steps detailed in the document Connecting to the University Database from Home included alongside this handout on Learn. This will require you to modify the .env file and run an ssh command.

• Your .env file should never be version controlled, especially if it contains sensitive information like passwords. If you are using git to keep track of your completed labs it may pay to include a .gitignore5file at the root of your project.

2 Setting up our Node application with TypeScript

2.1 Installing Node Packages with a package.json File

All Node.js projects contain a file (usually6 at the project root) named package.json that holds various metadata relevant to the project. The file is used to give information to npm that allows it to identify the project as well as handle the project’s third-party dependencies. It can also contain other metadata such as a project description, the version of a project in a particular distribution, license information, and configuration data – all of which can be vital to both npm and the end-users of a package.

Now we will start creating a chat application similar to what we worked on last week, covering the new concepts introduced in this lab. This is quite a technical step up compared to last lab, so feel free to work with or discuss the new concepts with others or the tutors.

1. Create a new directory called lab_2 (or something you prefer, though you may need to change this in some commands as well)

2.  Inside this new directory, create a file called package.json and insert the code from Listing 1 into it.

1    {

2               "name" :  "lab_2_combined" ,

3               "version" :  "1.0.0" ,

4               "description" :  "Combined  persistence,  architecture,  and  typescript labs  for  2022" ,

5               "main" :  "dist/app .js" ,

6               "scripts" :  {

7                          "prebuild" :  "tslint  -c  tslint .json  -p  tsconfig .json  --fix" ,

8                          "build" :  "tsc" ,

9                          "prestart" :  "npm  run  build" ,

10                          "start" :  "node  . " ,

11                          "test" :  "echo \"Error :  no  test  specified\"  &&  exit  1"

12               } ,

13               "author" :  "Morgan  English" ,

14               "license" :  "ISC" ,

15               "dependencies" :  {

16                          "dotenv" :  "^16 .0 .3" ,

17                          "express" :  "^4 .18 .2" ,

18                          "mysql2" :  "^2 .3 .3" ,

19                          "winston" :  "^3 .8 .2" ,

20                          "ajv" :  "^8 .11 .0"

21               } ,

22               "devDependencies" :  {

23                          "@types/express" :  "^4 .17 .15" ,

24                          "@types/node" :  "^18 .11 .18" ,

25                          "tslint" :  "^6 .1 .3" ,

26                          "typescript" :  "^4 .9 .4"

27               }

28    }

Listing 1: A basic package.json file for an express application with TypeScript

•  If you copy the above code to paste in your project, make sure there are no extra empty spaces between keywords and values as it can affect the parsing. The best – and recommended – way is to type it out from scratch rather than copy-pasting.

• We have introduced a lot in this file:

dependencies tell npm which packages are required to build and run your app, with

devDependencies being similar but specifically for packages only required for developing your ap- plication. In these dependencies you can set the necessary version for each required package using semantic versioning.

scripts are the commands that will run under the hood when you run your app with the com- mand npmrun. Notice that we have introduced some TypeScript and linting in the (pre)building stages, a required step when working with TS. The most important of these scripts is npm run start which is used to run your application.

For further reading refer to https://docs.npmjs.com/files/package.json

• The keyword main refers to the primary entry point of your application, the exports from this file will be included if someone imports your package.

3.  Now in your terminal7, navigate to your project directory and run npminstall. Node.js will create a new dir- ectory in your project folder named node_modules and will install the dependencies listed in the package.json file here. You may notice there are way more than you expected, these are mainly inherited dependencies from those we explicitly define.

4.  Now we need to setup our TypeScript config8so that our .ts files accurately build to JavaScript with the build scripts we defined earlier. Create a new file tsconfig.json in your root directory and add the code in Listing 2.

1 {

2 "compilerOptions" : {

3 "module" : "commonjs" ,

4 "target" : "es6" ,

5 "rootDir" : " ./src/ " ,

6 "outDir" : "dist" ,

7 "esModuleInterop" : true ,

8 "noImplicitAny" : true ,

9 "resolveJsonModule" :true ,

10 "sourceMap" : true

11 }

12 }

Listing 2: A basic tsconfig.json file.

5. For this project we also make use of tslint9, a linter for TypeScript.  Linters allow for catching issues with coding practices before we run the application which helps to catch errors and keep our code uniform. Create a new file tslint.json in your root directory and add the code in Listing 3.

1 {

2 "defaultSeverity" : "error" ,

3 "extends" : [

4 "tslint :recommended"

5 ] ,

6 "jsRules" : {} ,

7 "rules" : {

8 "trailing-comma" : [ false ]

9 } ,

10 "rulesDirectory" : []

11 }

Listing 3: A basic tslint.json file.

6. Create a folder src, this is where we will be storing all of our code. Within this folder create a file app.ts. Note: This should be the same as the‘main’variable in our package.json, however when building with TypeScript our app.ts will be transformed into a JavaScript file in the build folder dist. Thus src/app.ts becomes dist/app.js.

We are now ready to start coding our API!

2.2 Structuring Large Applications and MVC

Now that we have our modules installed, we can begin to develop our app. We want to break up the structure of our application to make it easier to understand for developers and ensure our application scales well with minimal refactoring required.

2.2.1 Model View Controller Architecture (MVC)

MVC is an architectural pattern used to break up the structure of an application into its conceptual counterparts. Anything relating to domain elements or interactions with databases comes under the model section, anything that relates to the presentation or the interface comes under the view section, and finally all the application logic is stored under the controller section.

In our application, we store each part of the MVC structure in its own directory. As our API has no‘view’we use a routes directory to provide the definition of the endpoints of our API.

1. Create two directories in your project (within the src folder we created earlier) called config and app.

2.  Inside the app directory, add three more directories routes, models, and controllers.

3.  In the config directory, create a file called db.ts and copy the code from Listing 4. Notably this file exports two functions, one to create a connection with the database and another to get access to a pool of connections that we can run queries on.

1 import mysql from 'mysql2/promise' ;

2 import dotenv from 'dotenv ' ;

3 import Logger from ' ./logger' ;

4 dotenv .config();

5

6 const state =  {

7 // @ts-ignore

8 pool : null

9 };

10

11 const connect = async (): Promise<void>  => {

12 state .pool = await mysql .createPool(  {

13 host : process .env .SENG365_MYSQL_HOST,

14 user :  process .env .SENG365_MYSQL_USER,

15 password :  process .env .SENG365_MYSQL_PASSWORD,

16 database :  process .env .SENG365  MYSQL DATABASE,

17