KANNIKA LIBRETA
  • Home
  • Kotlin & Spring Boot

~

Intro

Node.js is an open source server environment (=backend framework) that allows you to run JavaScript on the server

Node.js files
  • contain tasks that will be executed on certain events (ie: someone trying to access a port on the server)
  • ​must be initiated first on server

Node.js uses asynchronous programming!

A common task for a web server => open a file on the server and return the content to the client
    *Here is how PHP or ASP handles a file request:

1. Sends the task to the computer's file system
2. Waits while the file system opens and reads the file
3. Returns the content to the client
4. Ready to handle the next request
    *Here is how Node.js handles a file request:

1. Sends the task to the computer's file system
2. Ready to handle the next request
3. When the file system has opened and read the file, the server returns the content to the client
Node.js runs single-threaded, non-blocking, asynchronous programming, which is very memory efficient

Node.js can
  • generate dynamic page content
  • create, open, read, write, delete, and close files on the server
  • collect form data
  • add, delete, modify data in database

Hello Kannika example

  • myfirst.js
​
var http = require('http');

/* createServer() method to creates an HTTP server that listens to server ports and gives a response back to the client */
http.createServer(function (req, res) {
  //write a response to the client
  res.writeHead(200, {'Content-Type': 'text/html'});
  //end the response
  res.end('Hello Kannika!');
}).listen(8080);
  • -

On terminal run:$ node myfirst.js

Go to http://localhost:8080 to see the message

The function passed into the http.createServer() method, will be executed when someone tries to access the computer on port 8080
HTTP Header
HTTP Header
If the response from the HTTP server is supposed to be displayed as HTML, you should include an HTTP header with the correct content type

var http = require('http');
/* req arg - represents the request from the client as an object
This object has a property called "url" which holds the part of the url that comes after the domain name */

http.createServer(function (req, res) {
  /* res.writeHead: 1st arg - status code (200 = all ok) ; 2nd arg - object w/ response headers */
  res.writeHead(200, {'Content-Type': 'text/html'});
  res.write('Hello World!');
  res.end();
}).listen(8080);
Reading query string from Url
Example1: Read the query string

var http = require('http');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/html'});
  //Return the url part of the request object
  res.write(req.url);
  res.end();
}).listen(8080);

Goto: http://localhost:8080/summer
Output: /summer

Example2: split the query string into readable parts

var http = require('http');
var url = require('url');    // built-in module to split the query string into readable parts
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/html'});
  var q = url.parse(req.url, true).query;
  var txt = q.year + " " + q.month;
  res.end(txt);
}).listen(8080);

Goto: http://localhost:8080/?year=2023&month=March
Output: 2023 March

Modules

Modules are about the same as JavaScript libraries - A set of functions you want to include in your application

To include a module, use the require() function with the name of the module, for ex:
  • var http = require('http');
  • // HTTP module, which allows Node.js to transfer data over the Hyper Text Transfer Protocol (HTTP)
​​
Creating your own modules
Creating your own modules example
  • myfirstmodule.js
// Use the exports keyword to make properties and methods available outside the module file
exports.myDateTime = function () {
  return Date();
};
  • mainfile.js
var http = require('http');
var dt = require('./myfirstmodule');

http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/html'});
  res.write("The date and time are currently: " + dt.myDateTime());
  res.end();
}).listen(8080);
  • -
On terminal run:$ node mainfile.js
​
Go to http://localhost:8080 to see the message

File Systems

Node.js can act as a file server: read, create, update, delete, rename files
Read Files
  • server.js
var http = require('http');
var fs = require('fs');
http.createServer(function (req, res) {
  fs.readFile('demofile1.html', function(err, data) {
    res.writeHead(200, {'Content-Type': 'text/html'});
    res.write(data);
    return res.end();
  });
}).listen(8080);
  • index.html
<html>
<body>
<h1>My Header</h1>
<p>My paragraph.</p>
</body>
</html>

​
  • On terminal run:$ node server.js
  • Go to http://localhost:8080 to see the message
Create/Update Files

var fs = require('fs');
/* For all 3 bellow methods: If the file does not exist, a new file will be created */
fs.appendFile('mynewfile1.txt', 'Hello content!', function (err) {    // appends specified content to a file
/* fs.open() method takes a 2nd arg, if the flag is "w" = "writing", the specified file is opened for writing */

// OR: fs.open('mynewfile2.txt', 'w', function (err, file) {    // replaces the specified file and content if it exists
// OR: fs.writeFile('mynewfile3.txt', 'Hello content!', function (err) {

  if (err) throw err;
  console.log('Saved!');
});
Delete Files

var fs = require('fs');
fs.unlink('mynewfile2.txt', function (err) {    // Deletes the mentioned file
  if (err) throw err;
  console.log('File deleted!');
});

Rename Files

var fs = require('fs');
fs.rename('mynewfile1.txt', 'myrenamedfile.txt', function (err) {
  if (err) throw err;
  console.log('File Renamed!');
});

URL Module

Splitting a web address into readable parts
var url = require('url');
var adr = 'http://localhost:8080/default.htm?year=2023&month=march';
/* return a URL object with each part of the address as properties */
var q = url.parse(adr, true);

console.log(q.host); //returns 'localhost:8080'
console.log(q.pathname); //returns '/default.htm'
console.log(q.search); //returns '?year=2023&month=march'

var qdata = q.query; //returns an object: { year: 2023, month: 'march' }
console.log(qdata.month); //returns 'march'
Page Routing example
  • fileserver.js
var http = require('http');
var url = require('url');
var fs = require('fs');

http.createServer(function (req, res) {
  var q = url.parse(req.url, true);
  var filename = "." + q.pathname;
  fs.readFile(filename, function(err, data) {
    if (err) {
      res.writeHead(404, {'Content-Type': 'text/html'});
      return res.end("404 Not Found");
    } 
    res.writeHead(200, {'Content-Type': 'text/html'});
    res.write(data);
    return res.end();
  });
}).listen(8080);
  • summer.html
<!DOCTYPE html>
<html>
<body>
<h1>Summer</h1>
<p>I love the sun!</p>
</body>
</html>


  • winter.html
<!DOCTYPE html>
<html>
<body>
<h1>Winter</h1>
<p>I love the snow!</p>
</body>
</html>

​On terminal run:$
node fileserver.js
Go to:
  •  http://localhost:8080/summer.html to see the summer page
  • http://localhost:8080/winter.html to see the winter page

NPM

package manager for Node.js packages/modules
:$ npm install package-name    (used inside a directory for that specific project)
:$ npm install -g package-name    (executed externally/globally for all repo uses)
NPM creates a folder named "node_modules", where the package will be placed. All packages installed in the future will be placed in this folder.
NPM example
Example: Installing a package called 'upper-case'

On terminal:> npm install upper-case

/* Once the package is installed, include the "upper-case" package the same way as any other module */
var http = require('http');
var uc = require('upper-case');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/html'});
  res.write(uc.upperCase("Hello World!"));
  res.end();
}).listen(8080);

Events

​Every action on a computer is an event. Like when a connection is made or a file is opened.
Example 1 (Basic)
Example 1

/* readStream object fires events when opening and closing a file */
var fs = require('fs');
var rs = fs.createReadStream('./demofile.txt');
rs.on('open', function () {
  console.log('The file is open');
});
Events Module
Built-in module, called "Events", where you can create-, fire-, and listen for- your own events. A
ll event properties and methods are an instance of an EventEmitter object. To be able to access these properties and methods, create an EventEmitter object.
Example 2 (Custom)
Example 2
var events = require('events');
var eventEmitter = new events.EventEmitter();

//Create an event handler
var myEventHandler = function () {
  console.log('I hear a scream!');
}

//Assign the event handler to an event
eventEmitter.on('scream', myEventHandler);

//Fire the 'scream' event
eventEmitter.emit('scream');

Uploading Files

:$ npm install formidable
// and include it: var formidable = require('formidable'); 
Now we are ready to make a web page in Node.js that lets the user upload files to your computer
File Upload example
var http = require('http');
/* Formidable module to be able to parse the uploaded file once it reaches the server. When the file is uploaded and parsed, it gets placed on a temporary folder on your computer */
var formidable = require('formidable');
var fs = require('fs');

http.createServer(function (req, res) {
  if (req.url == '/fileupload') {
    var form = new formidable.IncomingForm();
    /* path to this temp directory where uploaded file is stored can be found in the "files" object, passed as the 3rd arg in the parse() method's callback function */
    form.parse(req, function (err, fields, files) {
      // move the file to the folder of your choice, use the File System module to rename the file
      var oldpath = files.filetoupload.filepath;
      var newpath = 'C:/Users/Your Name/' + files.filetoupload.originalFilename;
      fs.rename(oldpath, newpath, function (err) {
        if (err) throw err;
        res.write('File uploaded and moved!');
        res.end();
      });
 });
  } else {    // Below code creates a HTML form with an upload field that allows user to upload files
    res.writeHead(200, {'Content-Type': 'text/html'});
    res.write('<form action="fileupload" method="post" enctype="multipart/form-data">');
    res.write('<input type="file" name="filetoupload"><br>');
    res.write('<input type="submit">');
    res.write('</form>');
    return res.end();
  }
}).listen(8080);

Sending Emails

:$ npm install nodemailer
Sending email example
var nodemailer = require('nodemailer');

var transporter = nodemailer.createTransport({
  service: 'gmail',
  auth: {
    user: 'youremail@gmail.com',
    pass: 'yourpassword'
  }
});

var mailOptions = {
  from: 'youremail@gmail.com',
  to: 'myfriend@yahoo.com',   
  // to: 'myfriend@yahoo.com, myotherfriend@yahoo.com',    // to send email to multiple receivers
  subject: 'Sending Email using Node.js',
  text: 'That was easy!'
  // html: '<h1>Welcome</h1><p>That was easy!</p>'    // sending html formatted text instead of plain text
};

transporter.sendMail(mailOptions, function(error, info){
  if (error) {
    console.log(error);
  } else {
    console.log('Email sent: ' + info.response);
  }
});

Express JS

ExpressJS is a Node.js framework that provides a set of features for web&mobile applications.

Setup
Create an empty folder and cd into it
:$ npm init    (keep pressing enter until it asks for author name - type your full name)
:$ npm install --save express    (command used to install express)
:$ npm install -g nodemon    (nodemon helps automatically restart server without stoping and running it again)
Create a file: server.js
var express = require('express');
var app = express();

/* app.get(route, callback)
    This below 3 lines tells us what to do when a get request at the given route is called   */

app.get('/', function(req, res){    
   res.send("Hello Kannika!");
});

// below function binds and listens for connections on the specified host (by default = localhost) and port
app.listen(8080);

On terminal, execute:$ nodemon server.js
and goto http://localhost:8080

Routing

Routing example
  • index.js
var express = require('Express');
var app = express();

var things = require('./things.js');

//both index.js and things.js should be in same directory
app.use('/things', things);
/* function call on route '/things' attaches the things router with this route. Now whatever requests our app gets at the '/things', will be handled by our things.js router */

app.listen(8080);
  • things.js
var express = require('express');
var router = express.Router();

/* The '/' route in things.js is actually a subroute of '/things' */
router.get('/', function(req, res){
   res.send('GET route on things.');
});
router.post('/', function(req, res){
   res.send('POST route on things.');
});

//export this router to use in our index.js
module.exports = router;
To see the output, goto: localhost:8080/things/

Most Common HTTP methods
  • DELETE   -   delete the specified resource
  • PUT   -   modifies an existing object specified in the URI (if non-existent => create one)
  • POST   -   add a new object mentioned in the URI
  • GET   -   request a representation of the specified resource

URL Building / Dynamic Routing

Dynamic routing example
var express = require('express');
var app = express();

// Use regex to restrict URL
app.get('/things/:id([0-9]{5})', function(req, res){
   res.send('Matched first with proper 5-digit id: ' + req.params.id);
});

// req.params can be used to access all the params passed in the url
app.get('/things/:name/:id', function(req, res) {
   res.send('Matched second with name and then, id - id: ' + req.params.id + ' and name: ' + req.params.name);
});

// To see output, goto: http://localhost:8080/123
app.get('/:id', function(req, res){
   res.send('Matched third with random number as id - The id you specified is ' + req.params.id);
});

//Other routes can go here 
/* Below chunk should go after all other routes as Express matches routes from start to end */

app.get('*', function(req, res){
   res.send('Sorry, this is an invalid URL.');
});

app.listen(8080);

Middleware

Something that runs between the time the server gets the request and when the server sends the request 
Middleware example
​var express = require('express');
var app = express();

// Note3: making the middleware function global middleware
app.use(logger);

/* Note1: The function inside the app.get is essentially a middleware because
it happens before the server sends ot a response to the client but 
after receiving a request
*/

app.get('/', function(req, res){
   console.log("Home Page"); // Gets logged on console 2nd - depending on url
   res.send("Home Page");
});

// Note6: app.get can take in multiple functions as middleware
app.get('/users', auth, function(req, res){
   console.log("Users Page"); // Gets logged on console 2nd - depending on url *(3rd after Note5)
   console.log(`User is admin = ${req.admin}`) // Note7: Part2
   res.send("Users Page");
});

// Note2: middleware function
function logger(req, res, next) {
   console.log("Log"); // Gets logged on console 1st
   // By calling next, we are calling the next piece of middleware in-line

   next();
}

// Note5: Another type of middleware function
function auth(req, res, next) {
   //Note7: Performing authentication
   if (req.query.admin === 'true'){
      req.admin = true; // Setting it to access in next middleware
      next();  // when url is http://localhost:8080/users?admin=true
   }else{
      res.send("No authentication");  // when url is: http://localhost:8080/users
   }
   console.log("Auth"); // Gets logged on console 2nd
   //next(); // next() does not act like a return function, code after next() will get executed or cause error
}

app.listen(8080);

// Note4: Goto http://localhost:8080/users and click refresh to see what gets logged in the console

Template Engine: Pug

:$ npm install pug --save
rough draft example
  • index.js
var express = require('express');
var app = express();
app.set('view engine', 'pug');
app.set('views','./views');

app.get('/first_template', function(req, res){
   res.render('first_view', {
        name: "KanKan",
        url:"http://kannikakabilar.github.io",
        user: {name: "Kannika", age: "24"}
   });
});​

app.listen(8080);
* Pug converts this very simple looking markup to html. The left-side file gets converted into the right-side file.
  • first_view.pug
doctype html
html
   head
      title = "Hello Pug"
   body
      h1 Welcome to Pug
      p.greetings#people Hello World!

      //This is a Pug comment - above chunk translates to =>
      div
         | To insert multiline text, 
         | You can use the pipe operator.
      div.
         But that gets tedious if you have a lot of text. You can use "." ​             at the end of tag to denote block of text. To put tags inside ​               this block, simply enter tag in a new line and indent it-accord.
      
      h1=name
​      h1 Greetings from #{name}
      a(href = url) URL​
      if(user)
         h1 Hi, #{user.name}
      else
         a(href = "/sign_up") Sign Up
<!DOCTYPE html>
<html>
   <head>
      <title>Hello Pug</title>
   </head>
   
   <body>
      <p class = "greetings" id = "people">Hello World!</p>
   </body>
</html>
Basic Example
  • server.js
const express = require('express');
const app = express();

const port = 8080;
const host = 'localhost';

// below 2 lines are used when working with pug
app.set('views', './views');
app.set('view engine', 'pug');

// below looks for inex.pug file to display at route: '/'
app.get('/', (req, res) => {
res.render('index');
});

app.listen(port, host, () => {
console.log(`Server started at ${host} port ${port}`);
});
  • /views/index.pug (create a views folder inside root directory and index.pug file inside views folder)
doctype=html
html
head
title Express.js + Pug
body
h1 Welcome to Express.js + Pug


// * Pug converts this very simple looking markup to html
Slightly Advanced example
  • server.js
const express = require('express');
const app = express();
const port = 8080;

app.set('views', './views');
app.set('view engine', 'pug');

app.get('/', (req, res, next) => {
res.render('index');
});

/* sending info through url and storing the values in an object so that it can be accessed by the pug file in views/ */
app.get('/member/:name/planet/:home', (req, res) => {
const memberDetails = {
member: req.params.name,
planet: req.params.home
}
res.render('guardian', memberDetails);
});

app.get('*', (req, res, next) => {
res.status(200).send('Sorry, page not found');
next();
});

app.listen(port, () => {
console.log(`Server started at port ${port}`);
});
  • /views/guardian.pug
doctype html
html
  head
    title Express.js + Pug Demo
  body
    h1 Welcome, Guardian!
    div Member: #{member}
    p Planet: #{planet}


// run :$ node server.js
// goto: http://localhost:8080/member/Rocket/planet/Neptune

Form Data

:$ npm install --save body-parser multer
Form example
  • index.js
var express = require('express');
var bodyParser = require('body-parser');
var multer = require('multer');
var upload = multer();
var app = express();

app.get('/', function(req, res){
   res.render('form');
});

app.set('view engine', 'pug');
app.set('views', './views');

// for parsing application/json
app.use(bodyParser.json()); 

// for parsing application/xwww-
app.use(bodyParser.urlencoded({ extended: true })); 
//form-urlencoded

// for parsing multipart/form-data
app.use(upload.array()); 
app.use(express.static('public'));

app.post('/', function(req, res){
   console.log(req.body);
   res.send("recieved your request!");
});
app.listen(8080);
  • form.pug
html
html
   head
      title Form Tester
   body
      form(action = "/", method = "POST")
         div
            label(for = "say") Say:
            input(name = "say" value = "Hi")
         br
         div
            label(for = "to") To:
            input(name = "to" value = "Express forms")
         br
         button(type = "submit") Send my greetings
​

:$ nodemon index.js

Cookies

Cookies are small files/data that are sent to client with a server request and stored on the client side. Every time the user loads the website back, this cookie is sent with the request. This helps us keep track of the user’s actions.
​
:$ npm install --save cookie-parser
Cookies example
  • server.js
const cookieParser = require("cookie-parser");
const express = require('express');
const app = express();
const PORT = 8080;

app.use(cookieParser());
 
// With middleware - sends cookie with name variable and it contains value: 'CookieKannika'
// 'Cookie Set' is returned to the webpage

app.use('/', function (req, res, next) {
    res.cookie('name', 'CookieKannika');
    res.send("Cookie Set");
    next();
})
 
// req.cookies is an object that contains cookies variables stored from user-side
app.get('/', function (req, res) {
    console.log('Cookie SET');
    console.log(req.cookies);
});
/* Output: 
Cookie SET
{ name: 'CookieKannika' } */

app.listen(PORT, function (err) {
    if (err) console.log(err);
    console.log("Server listening on PORT", PORT);
});

Sessions

Cookies and URL parameters are both suitable ways to transport data between the client and the server. But they are both readable and editable on the client side. Sessions solve exactly this problem. You assign the client an ID and it makes all further requests using that ID. Information associated with the client is stored on the server linked to this ID.

:$ npm install --save express-session
Sessions Example
var express = require('express');
var cookieParser = require('cookie-parser');
var session = require('express-session');

var app = express();

app.use(cookieParser());
app.use(session({secret: "Shh, its a secret!"}));

app.get('/', function(req, res){
   if(req.session.page_views){
      req.session.page_views++;
      res.send("You visited this page " + req.session.page_views + " times");
   } else {
      req.session.page_views = 1;
      res.send("Welcome to this page for the first time!");
   }
});
app.listen(8080);

Database

:$ npm install express mongoose --save
Connecting to mongo DB example
const express = require('express');
const mongoose = require('mongoose');

// Below uri is unique to the database that you want to connect
const uri = "mongodb+srv://kanns1999:KannikaSoftwareEngineer99@mongoexpresscluster.zbimusl.mongodb.net/?retryWrites=true&w=majority";

async function connect () {
    try {
        await mongoose.connect(uri);
        console.log("Connected to MongoDB");
    } catch (e) {
        console.error(e);
    }
}

connect();

const app = express();
app.listen(8080, () => {
    console.log("Server Started");
});

Error Handling

Error Handling Example
var express = require('express');
var app = express();

app.get('/', function(req, res){
   //Create an error and pass it to the next function
   var err = new Error("Something went wrong");
   next(err);
});

/*
 * other route handlers and middleware goes here
 * ....
 */

//Error handling middleware - needs to have the 'err' argument

app.use(function(err, req, res, next) {
   res.status(500);
   res.send("Oops, something went wrong.")
});

app.listen(8080);

RESTful API

The first 100 seconds explains it all (or enough)
Extras: Directory Structure, scaffolding, Static Files, Debugging
Directory Structure
test-project/
   node_modules/
   config/
      db.js                //Database connection and configuration
      credentials.js       //Passwords/API keys for external services used by your app
      config.js            //Other environment variables
   models/                 //For mongoose schemas
      users.js
      things.js
   routes/                 //All routes for different entities in different files 
      users.js
      things.js
   views/
      index.pug
      404.pug
        ...
   public/                 //All static content being served
      images/
      css/
      javascript/
   app.js
   routes.js               //Require all routes in this and then require this file in 
   app.js 
   package.json
Scaffolding - creates a skeleton for web applications, instead of manually creating public directory, adding middlewares and route files, and etc. A scaffolding tool (like Yeoman) sets up all these things for us so that we can directly get started with building our application.

Static Files - 
Used for css, img, and extra javasrcipt (animation) files

Debugging - :$ DEBUG=express:application node index.js
Create a free web site with Weebly
  • Home
  • Kotlin & Spring Boot