0% found this document useful (0 votes)
3 views36 pages

04 Nodejs PDF

Uploaded by

prabhath malinda
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)
3 views36 pages

04 Nodejs PDF

Uploaded by

prabhath malinda
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/ 36

Session 4: Node.

js Packages & Express JS


Full-Stack Development

Mark Dixon

School of Engineering, Computing and Mathematics


Scrum Standup: Last Session
• What did we do last session

• Progress:
did you learn anything (was anything particularly useful or good)?
(write down topics, what you can remember)

• Problems / Blockers:

How did the lab session go (were you able to get something running)?

What could be better?

2
Introduction
Today’s topics
1. Node.js packages
• Creating custom packages within a project
• Importing existing packages
2. ExpressJS

Session learning outcomes – by the end of today’s lecture you will be able to:
• employ Packages within Node.js to improve server-side application design
• use Express.JS to create efficient webservice APIs for serving application content

3
Node.js Request object (Routing)
server.js
• Request object, access to: let url = require("url");
• Path let http = require("http");
let port = 9000;
• Query String
let server = http.createServer(
function(request, response) {
let path = request.url;
let args = url.parse(request.url, true).query;
if (path.startsWith("/hello")){
let message = "Hello there " + args.personName;
response.end(message);
}else{
response.end("Error - Page not found!");
}
}
);

server.listen(port, function() {
console.log("Server listening on port " + port);
});

4
Node.js Packages - Building your own packages
1. Refactor the code – create sayHello function and move to functions.js
2. Export the function so that it is available to other packages

functions.js

function sayHello(personName) {
if (personName === undefined) {
return "Hello there nameless person";
}
return "Hello there " + personName;
}

module.exports.sayHello = sayHello;

5
Node.js Packages - Using your own packages
1. Export the function
2. Import functions.js into the webserver and reference its sayHello function
Note:
server.js - the ./
- no .js file extension
let url = require("url");
let http = require("http");
let functions = require("./functions");
let port = 9000;

let server = http.createServer(function(request, response) {


let args = url.parse(request.url, true).query;
response.end(functions.sayHello(args.personName);
});

server.listen(port, function() {
console.log("Server listening on port " + port);
});
6
Node packages & NPM
NPM offers a large collection of packages – offering a wide range of functionality
for your Node applications
• Database access
• Image manipulation
• AI – neural networks, evolutionary algorithms…
• Security

Install with the command npm install packagename


• https://www.npmjs.com/

7
package.json
The package.json file stores metadata about an application
• Compulsory fields name and version
• Run npm init and answer the questions
• Use npm install to install with the same dependencies as the developer
{
"name": "test_package",
"version": "1.0.0",
"description": "This is a package to show how package.json works",
"main": "app.js",
"repository": {
"type": "git",
"url": "git+https://github.com/djw213/test-package.git"
},
"author": "Mark Dixon <[email protected]>",
"homepage": "https://github.com/djw213/test-package#readme",
}
8
Data representation
HTML can be added to the DOM directly
let elem = document.getElementById("document");
elem.innerHTML = response.responseText;

XML data can be queried like the DOM


let x = xmlhttp.responseXML.getElementsByTagName("PERSON");

JSON structured by the JSON.parse method – converted to a JavaScript object


let data = JSON.parse(response.responseText);

9
MEAN (and MERN) web apps

10
MVC
• Model: holds the data model
• View: presentation code
• Controller: sits between the 2 previous layers & passes data back and forth
reacts to events in UI & calls methods in model

• Advantages of MVC:
• Can have multiple views on the same data model
• Supports loose coupling – so promotes good software engineering practice
• Lends itself to team development, and can have specialists working on their tier
• Disadvantage
• can introduce unnecessary complexity to some projects

11
Express JS: Hello World
...with an anonymous function
let express = require("express");
let app = express();
app.get("/sayHello", function(request, response) {
response.send("Hello World, from Express");
});
app.listen(9000);

…with a named function


let express = require("express");
let app = express();
function sayHello(request, response) {
response.send("Hello World, from Express");
}
app.get("/sayHello", sayHello);
app.listen(9000);
12
Express JS: Routes
Express supports lots of HTTP methods
• We will consider get and post
• Have a look at https://expressjs.com/en/4x/api.html#app.METHOD for more
details

JS function (e.g. sayHello)

app.get(path, callback);

extracted from query

• Same pattern for post messages

13
Express JS: Templates
• Combine templates with data to produce HTML content to send to the client
• Construct template file(s) – .ejs extension
• Control flows <% %> and insert content <%= %>
mypage.ejs • Include route - renders template ("/page")
<html> let express = require("express");
<head> let path = require("path");
<title>Page Template</title> let app = express();
</head>
<body> app.set("views", path.join(__dirname, "views"));
<h1>Page Title</h1> app.set("view engine", "ejs");
<p>
The message is: '<%= msg %>' app.get("/page", function(request, response) {
</p> let pageData = {"msg": "Hello World, from template"};
</body> response.render("mypage", pageData);
</html> });

app.listen(9000, function() {
console.log("Listening on 9000");
});
14
Express JS: Static resources

app.use(express.static(path.join(__dirname, "files")));

• Specify where your static resources live


• path.join concatenates paths and filenames
• __dirname is built in shorthand for the current directory

15
Express JS: Static resources
Modify the app
app.use(express.static(path.join(__dirname, "statics")));

Modify the template – link to CSS…


<link rel="stylesheet" href="/css/style.css" />

…and add a picture


<img src="/imgs/PSQ.jpg" />

16
Express JS: Project structure

17
Express JS: Sending data – get with an ID
let express = require("express");
let app = express();

function sayHello(req, res) {


let users = ["Joan", "John"];
let userId = req.params.userid;

if (userId >= users.length) {


res.send("Invalid user");
} else {
res.send("Hello " + users[userId]);
}
}

app.get("/sayhello/:userid", sayHello);
app.listen(9000);
module.exports.app = app;
18
Express JS: Sending data - post
• Need to parse the body of the post message
• Use the Node package body-parser
• May need to install
let express = require("express");
let bodyParser = require("body-parser");

app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));

app.post("/api/test", function(request, response) {


let name = request.body.name;
let age = request.body.age;
console.log("Name: ‘" + name + "’, age: " + age);
});

19
Express JS: Test with a basic client
<form action="http://localhost:9000/api/test" method="post">
<p>Name <input type="text" name="name" /></p>
<p>Age <input type="number" name="age" /></p>
<input type="submit" />
</form>

20
Express JS: Sessions
• Save values on the server between page serves
• Secret key used to signing/encrypting cookies
let session = require("express-session");

app.use(session({secret: "Mark’s session secret"}));

app.get("/", function(request, response) {


if (request.session.mySessionVal) {
let msg = request.session.mySessionVal;
response.send("You’ve been here before: ‘" + msg + "’");
} else {
request.session.mySessionVal = "Value stored in session");
response.send("First visit – I’ve set a message for you");
}
});

21
Express JS: Validation

Exercise
Suggest validation approaches you
might apply to this web form – we will
discuss them after 5 minutes

Validation is important
• to provide a good user experience
• to avoid wasting machine resources
• to prevent security breaches

22
Static code analysis
JavaScript is a “sloppy” language
• Interpreted (no compile-time errors)
• Loosely typed (no type checking)

Allows a lot of badly structured code

Static code analysis tools (linters) lift syntax requirements and enforce them
• Reduce runtime errors
• Increase readability, scalability, maintainability

23
Static code analysis tools
• JSLint (original), JSHint (improved), ESLint (most up-to-date)

Running eslint locally


• Install: npm install eslint
• Initialise: .\node_modules\.bin\eslint --init
• Run: .\node_modules\eslint yourfile.js

24
Exercise 1: Single Container Node.js stack using Docker
• The following example uses an Node.js image to deploy your JS server file into a
Docker container. You can do everything on the host machine (i.e. your laptop or
desktop PC), but this is usually discouraged.
• Create new folder ‘demoExpress’ (referred to here as the project folder)

• Create new folder ‘app’ (inside previous folder)

• Terminal into project folder (on your host - your laptop or desktop machine)
Check that Docker is installed (on the host):
docker --version

• Check that Docker is running (on the host):


docker ps

• Ensure you are in the project folder.

25
Exercise 1: Single Container Node.js stack using Docker
• Run a temporary Node.js container:

(git bash)
docker run -it --rm -v "`pwd -W`"/app:/usr/src/app --name temp node:18 bash

(Windows CMD)
docker run -it --rm -v "%cd%/app":/usr/src/app --name temp node:18 bash

(WSL Ubuntu, and Mac)


docker run -it --rm -v "$(pwd)/app":/usr/src/app --name temp node:18 bash

• This should show the bash prompt (you are now inside the container, not the host).

• Check that node.js is installed (inside the container):

node --version

• Check that npm is installed (inside the container):

npm --version

26
Exercise 1: Single Container Node.js stack using Docker
• Initialise our application:

cd /usr/src/app
npm init -y

• This should create a package.json file (with default values):

{
"name": "app",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}

• Update npm:

npm update

27
Exercise 1: Single Container Node.js stack using Docker
• Install express:

npm install express

• This installs express, and adds a dependency to the package.json file:

{
"name": "app",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"express": "^4.18.2"
}
}

• Exit the container (and return to the host):

exit

28
Exercise 1: Single Container Node.js stack using Docker
• Create new ‘server.js’ file (inside app folder)
Type the following into that file:

let port = 8080;


let express = require('express');
let app = express();

app.get('/', (req, res) => {


res.send('Hello there!!');
});

app.listen(port, () => {
console.log('Running on port: ' + port);
});

• Create new ‘startup.sh’ file (inside app folder)


Type the following into that file:

cd /usr/src/app
npm install
node server.js

29
Exercise 1: Single Container Node.js stack using Docker
• Create new file ‘compose.yaml’ (in project folder)
Type the following into that file:

services:
web:
image: node:18
volumes:
- ./app:/usr/src/app
ports:
- "82:8080"
command: sh -c "
chmod +x /usr/src/app/startup.sh &&
/usr/src/app/startup.sh"

• Create new ‘up.sh’ file (inside project folder)


Type the following into that file:

docker-compose up -d

• Terminal into project folder (on your host)


Start the application up:

. up.sh

• Navigate to “http://localhost:82/”, you should see a Hell World message.

30
Exercise 2: Red
• In this exercise you will create an http server with Node, along with a browser-based client that communicates with
it using Ajax. This server requires some more extensive routing logic.
• Begin by creating a server. To do this, make a copy of (the http) server.js (at the start of these slides) and update the
createServer function as follows:
let server = http.createServer(function(request, response) {
response.writeHead(200, {"Access-Control-Allow-Origin": "*"});
let urlParts = url.parse(request.url, true);
if (urlParts.path == "/red") {
response.end("<p>Here is some "
+ "<span style=\"color: red;\">red</span> text</p>");
} else {
response.end("<p>This is some plain text</p>");
}
});
• This code does two things. First, it adds a header to the response that allows communication between two
different hosts. It also produces the response for the case where the user requests the red API route, and the base
case where no route is specified.
• Once you have added the code above:
• Modify the server so that it provides a route for blue and green text.
• Write a HTML file that accesses the server and adds the server’s response to a div called content. If you are using vanilla JavaScript
you will need the innerHTML property, and with jQuery you’ll want the .html() method.

31
Exercise 3: Dice
• Implement a function that rolls a dice, generating random integers between 1 and 6
(inclusive), which are returned by the function. Once you have implemented the
function, expose the function you have written with a route in your Express API.
• This exercise is similar to the previous Express one, except that it requires you to
generate something (slightly) more interesting than the Hello World text. You should
start by building a function that returns a number from the set {1, 2, 3, 4, 5, 6}. To do
this, we use the following algorithm:
• Generate a random number between 0 and 0.999999… with Math.random
• Multiply that number by 6 (we are assuming a six-sided die) to give a number between 0 and
5.999999…
• We want an integer, so use Math.floor to round the number down (giving a number in the set {0,
1, 2, 3, 4, 5}).
• Add one to the number to put it between 1 and 6 (inclusive).
• Add the function to a file called functions.js and then implement an Express server that
exposes the function through a get API route. Load the route in your browser and you
should see the following output (the port number will depend on your code):

32
Exercise 3: Dice
• Express facilitates presentation on the web using templates. Add a template to the dice server that presents the
result of rolling the dice in the browser.
• To begin with you will need to create a directory in which to store the templates – call this views. Within that,
create a file called dicepage.ejs, and open this in your editor. Modify the file as follows:
<html>
<head>
<link rel="stylesheet" href="/dice.css" />
</head>
<body>
<h1>You rolled a <%= number %></h1>
<p>Refresh the page to roll again...</p>
<body>
</html>
• This is basically an HTML file that can be served by the Express app. The clever part is the <%= number %> element
– this enables you to pass in a variable called number which is evaluated when the template is executed.
• Having created the template you must now serve it from the app. You will need to use NPM to install the ejs
module. Then modify dice-server.js by adding the following lines after the declaration of the port number and
before the /roll route:
app.set("views", path.join(__dirname, "views"));
app.set("view engine", "ejs");
• This configures Express to use the appropriate template engine, and tells it where to find the templates (in the
views directory).

33
Exercise 3: Dice
• You then need to add another route that renders and serves the template (and its dice
roll):
response.render("dicepage", {number: num});
• Run the server, then browse to the /dicepage route, and you should see the following
output:

• Then, add some styling to the page using CSS. In the realm of Express, CSS is static
content, and you have to configure the app to load its static content from wherever you
have stored it. Create a directory called files and add the following CSS file (dice.css) :
body {
background-color: #bfd8ff;
font-family: Verdana, Geneva, Tahoma, sans-serif;
}
• Configure the app by adding the following line immediately after the EJS config code you
just added:
app.use(express.static(path.join(__dirname, "files")));
34
Exercise 3: Dice
• Finally, link the CSS to your template by adding the following line to your head
section:
• Re-run the server and navigate to the page in your browser, and you should see
the following:

• You’ve created several files – to make sure you’ve got them all in the right place,
here is the file structure you should be aiming for (assuming you’ve put all the
code into a directory called dice-app:

35
Exercise 4: Trains
• Re-create the Trains application (from last week) using Express.
• enable filtering on platform number. Modify the template so that it has a form looking
something like this:
• The text input’s name should be platform.
• Modify the Express app in the following ways to process the form:
• Modify the getTrains function to take an argument called platform and if a value is provided add
this to the filter object.
• Pass the platform element of the post data to the getTrains function.
• Add a post route to the station-app.js file.
• Modify the template to include a paragraph with a link back to the unfiltered list.
• When you have completed this exercise you should be able to enter the values 1, 2 or 3
into the box and click Submit to view only the specified platform. Clicking View all
platforms should return you to the original full list.
• Add some client-side and server-side validation to the search form. It should not be
possible to submit the search form without a value in the text field. If it is submitted, the
server should reject it with an error page.
36

You might also like