🖍️
Developer Note
  • Welcome
  • Git
    • Eslint & Prettier & Stylelint & Husky
  • Programming Language
    • JavaScript
      • Script Async vs Defer
      • Module
      • Const VS Let VS Var
      • Promise
      • Event Loop
      • Execution Context
      • Hoisting
      • Closure
      • Event Buddling and Capturing
      • Garbage Collection
      • This
      • Routing
      • Debounce and Throttle
      • Web Component
      • Iterator
      • Syntax
      • String
      • Array
      • Object
      • Proxy & Reflect
      • ProtoType
      • Class
      • Immutability
      • Typeof & Instanceof
      • Npm (Node package manager)
    • TypeScript
      • Utility Type
      • Type vs Interface
      • Any vs Unknown vs Never
      • Void and undefined
      • Strict Mode
      • Namespace
      • Enum
      • Module
      • Generic
    • Python
      • Local Development
      • Uv
      • Asyncio & Event loop
      • Context Manager
      • Iterator & Generator
      • Fast API
      • Pydantic & Data Class
    • Java
      • Compilation and Execution
      • Data Type
      • Enumeration
      • Data Structure
      • Try Catch
      • InputStream and OutputStream
      • Concurrent
      • Unicode Block
      • Build Tools
      • Servlet
      • Java 8
  • Coding Pattern
    • MVC vs MVVM
    • OOP vs Functional
    • Error Handling
    • MVC vs Flux
    • Imperative vs Declarative
    • Design Pattern
  • Web Communication
    • REST API
      • Web Hook
      • CORS issue
    • HTTPS
    • GraphQL
      • REST API vs GraphQL
      • Implementation (NodeJS + React)
    • Server-Sent Event
    • Web Socket
    • IP
    • Domain Name System (DNS)
  • Frontend
    • Progressive Web App (PWA)
    • Single Page & Multiple Page Application
    • Search Engine Optimiaztion (SEO)
    • Web bundling & Micro-frontend
      • Webpack
        • Using Webpack to build React Application
        • Using Webpack to build react library
      • Vite
      • Using rollup to build react library
      • Implementing micro frontend
    • Web Security
      • CSRF & Nonce
      • XSS
      • Click hijacking
    • Cypress
    • CSS
      • Core
        • Box Model
        • Inline vs Block
        • Flexbox & Grid
        • Pseudo Class
        • Position
      • Tailwind CSS
        • Shadcn
      • CSS In JS
        • Material UI
    • React
      • Core
        • Component Pattern
        • React Lazy & Suspense
        • React Portal
        • Error Boundary
        • Rendering Methods
        • Environment Variable
        • Conditional CSS
        • Memo
        • Forward Reference
        • High Order Component (HOC) & Custom Hook
        • TypeScript
      • State Management
        • Redux
        • Recoil
        • Zustand
      • Routing
        • React Router Dom
      • Data Fetching
        • Axios & Hook
        • React Query
        • Orval
      • Table
        • React Table
      • Form & Validation
        • React Hook Form
        • Zod
      • NextJS
        • Page Router
        • App Router
      • React Native
    • Angular
    • Svelte
      • Svelte Kit
  • Backend
    • Cache
      • Browser Cache
      • Web Browser Storage
      • Proxy
      • Redis
    • Rate limit
    • Monitoring
      • Logging
      • Distributed Tracing
    • Load Test
    • Encryption
    • Authentication
      • Password Protection
      • Cookie & Session
      • JSON Web Token
      • SSO
        • OAuth 2.0
        • OpenID Connect (OIDC)
        • SAML
    • Payment
      • Pre-built
      • Custom
    • File Handling
      • Upload & Download (Front-end)
      • Stream & Buffer
    • Microservice
      • API Gateway
      • Service Discovery
      • Load Balancer
      • Circuit Breaker
      • Message Broker
      • BulkHead & Zipkin
    • Elastic Search
    • Database
      • SQL
        • Group By vs Distinct
        • Index
        • N + 1 problem
        • Normalization
        • Foreign Key
        • Relationship
        • Union & Join
        • User Defined Type
      • NOSQL (MongoDB)
      • Transaction
      • Sharding
      • Lock (Concurrency Control)
    • NodeJS
      • NodeJS vs Java Spring
      • ExpressJS
      • NestJS
        • Swagger
        • Class Validator & Validation Pipe
        • Passport (Authentication)
      • Path Module
      • Database Connection
        • Integrating with MYSQL
        • Sequalize
        • Integrating with MongoDB
        • Prisma
        • MikroORM
        • Mongoose
      • Streaming
      • Worker Thread
      • Passport JS
      • JSON Web Token
      • Socket IO
      • Bull MQ
      • Pino (Logging)
      • Yeoman
    • Spring
      • Spring MVC
      • Spring REST
      • Spring Actuator
      • Aspect Oriented Programming (AOP)
      • Controller Advice
      • Filter
      • Interceptor
      • Concurrent
      • Spring Security
      • Spring Boot
      • Spring Cloud
        • Resilience 4j
      • Quartz vs Spring Batch
      • JPA and Hibernate
      • HATEOS
      • Swagger
      • Unit Test (Java Spring)
      • Unit Test (Spring boot)
  • DevOp
    • Docker
    • Kubernetes
      • Helm
    • Nginx
    • File System
    • Cloud
      • AWS
        • EC2 (Virtual Machine)
        • Network
        • IAM
          • Role-Service Binding
        • Database
        • Route 53
        • S3
        • Message Queue
        • Application Service
        • Serverless Framework
        • Data Analysis
        • Machine Learning
        • Monitoring
        • Security
      • Azure
        • Identity
        • Compute Resource
        • Networking
        • Storage
        • Monitoring
      • Google Cloud
        • IAM
          • Workload Identity Federation
        • Compute Engine
        • VPC Network
        • Storage
        • Kubernetes Engine
        • App Engine
        • Cloud function
        • Cloud Run
        • Infra as Code
        • Pub/Sub
    • Deployment Strategy
    • Jenkins
    • Examples
      • Deploy NextJS on GCP
      • Deploy Spring on Azure
      • Deploy React on Azure
  • Domain Knowledge
    • Web 3
      • Blockchain
      • Cryptocurrency
    • AI
      • Prompt
      • Chain & Agent
      • LangChain
      • Chunking
      • Search
      • Side Products
Powered by GitBook
On this page
  • Introduction
  • Separating Routes
  • Error Handling
  • Template Engine
  • Session & Cookie
  • Flash message
  • CSRF Token
  • File Handling
  • Upload
  • Download
  • Deployment
  • Pre-action
  • Https
  • Forever

Was this helpful?

  1. Backend
  2. NodeJS

ExpressJS

PreviousNodeJS vs Java SpringNextNestJS

Last updated 17 days ago

Was this helpful?

Introduction

  • It is a framework that allows user to focus on developing business logic instead of typing boilerplate code for defining route and handling request and response

  • It is all about middleware that the incoming request will go through all the funnels and then send the response back to client side

  • The default query string parser is using qs library

const express = require("express");
const path = require("path");
const app = express();

// define middleware to parse body of request

// usally used for rest api, as the content-type is mainly application/json
// for parsing the request body as json
app.use(express.json());

// used to parse form data, as the content type is mainly 
// application/x-www-form-urlencoded
app.use(express.urlencoded({extended: false});

// override the query parser setting, the default value is "extended"
// however, the default depth of qs is 5, so needed to be increased when needed
app.set('query parser', (queryString) => {
    const qs = require('qs');
    return qs.parse(queryString, {
      depth: 100, // Increase depth limit from default 5
      arrayLimit: 100, // Optional: increase array items limit
      parameterLimit: 2000, // Optional: increase parameter count limit
    });
  });

// server static file, such as image
app.use(express.static(path.join("__dirname","public")));
// defining middleware globally
app.use((req,res,next)=>{
  console.log("middleware 1");
  // go to next middleware
  next();
});

app.use((req,res,next)=>{
  console.log("middleware 2");
  next();
});

// only applicable to "/halo" path
app.use("/halo",(req,res,next)=>{
  console.log("halo");
});

// only applicable to "/halo" path
app.use("/halo/:id",(req,res,next)=>{
  console.log("halo",req.params.id);
});

app.use("/halo",(req,res,next)=>{
  console.log("halo");
});

// only applicable for post method and path "/post"
app.post("/post", (req,res,next)=>{
  console.log(req.body);
});

// The code behind is to create http server, ...
app.listen(8080, function () { 
  console.log("Server Start "); 
});

Separating Routes

  • Express Router allows to divide paths into multiple files

// app.js

// Filtering the path to go into middleware
app.use("/auth", require("./routes/auth"));
app.use("/user", require("./routes/user"));

app.use((req,res)=>{
    res.send("Page not found");
});
// routes/user.js
const express = require("express");
const router = express.Router();

// only get methods and exact match to /user/test is applicable to this middleware
router.get("/test", function (req, res, next) {
  res.send("test");
});

module.exports = router;

Error Handling

// Define error middleware
app.use((error, req , res , next) =>{
        console.log(error.StatusCode);
        // ...
})

app.get("/test",(req,res,next)=>{
    try{
        // ...
    } catch (err){
        // automatically go to error middleware
        const error = new Error(err);
        error.StatusCode = 500;
        return next(error);
    }
})

Template Engine

  • The template engine is used to understand the certain syntax, and scan the html-ish template and then replace the placeholder from server

  • Finally, it will generate the html file


// Define which template template is using
app.set('view engine','ejs');
// Define the directory of template file, default: view
app.set('views','views');


// Automatically set the data to the view for every request
app.use(function(req,res,next){
     res.locals.success_msg = "...";
     res.locals.user_msg = "...";
     next();
});

app.get("/test", (req,res,next)=>{
   // output as test.html from test.ejs in view file
   res.render('test', {
        layout: null,
        username_msg: forgotusername
   }
});
<body>
  <center>
    <h1 style="font-size:40px">Hi!! <%=username_msg%></h1>
    <h2 style="font-size:30px">Reset Password</h2>
    Here is the link to reset your password:
    <a href="http://127.0.0.1:5000/users/resetpw?username=<%=username_msg%>&email=<%=email_msg%>">Reset</a>
  </center>
</body>

Session & Cookie

const session = require('express-session');
const MongoDBStore = require('connect-mongodb-session')(session);
const app = express();
const MONGODB_URI =
  'mongodb+srv://maximilian:9u4biljMQc4jjqbe@cluster0-ntrwp.mongodb.net/shop';
  
// Define the collection that store sessions  
const store = new MongoDBStore({
  uri: MONGODB_URI,
  collection: 'sessions'
});

// Define the session middleware
// Automatically parse the related cookie and find the related session information
// Automatically generate cookie, if the related cookie doesn't existed
app.use(
  session({
   // used to encrypt the session id, 
   // to make sure that only server can decrypt the id
    secret: 'my secret',
    // Prevent update session on each request
    resave: false,
    saveUninitialized: false,
    // Define the source of session storage, default is to using memory
    store: store,
    // The related cookies setting
    cookies:{
     // ...
    }
  })
);

// Login
// Set the session information and save into document
req.session.isLoggedIn = true;
req.session.user = user;
req.session.save(err => {
  console.log(err);
  res.redirect('/');
});

// Logout
// Delete the session from the storage
// Even the cookie contains session id, the related session will not be found
req.session.destroy(err => {
    console.log(err);
    res.redirect('/');
 });

Flash message

  • In order to provide user feedback while redirecting the response, flash message will be used

  • The message will be stored into session temporarily, when message has been used, the message will be pop up from the session

const flash = require('connect-flash');

app.get('/logout', function (req, res) {
  // add the message into storage
  req.flash('success_msg', 'You are successfully logged out');
  res.redirect('/users/login');
});

app.get("/login", (req,res) =>{ 
  //  get back the message from session and pop out
  let message = req.flash('error');
  if (message.length > 0) {
    message = message[0];
  } else {
    message = null;
  }
  res.render('auth/login', {
    path: '/login',
    pageTitle: 'Login',
    errorMessage: message
  });
})

CSRF Token

const csrf = require('csurf');
const csrfProtection = csrf();

// check the non-get route to see whether the csrf token is existed on request or not
app.use(csrfProtection);

app.use((req, res, next) => {
 // pass csrf token into view
  res.locals.csrfToken = req.csrfToken();
  next();
});
<form class="login-form" action="/login" method="POST">
    <input type="hidden" name="_csrf" value="<%= csrfToken %>">
</form>

File Handling

Upload

const multer = require('multer');

// To parse the request which type is multpart/form-data and contain file binary data
// define the storage location and stream the binary data to destination automatically
// decide which file type that will be processed
// set to req.file automatically
const fileStorage = multer.diskStorage({
  destination: (req, file, cb) => {
    cb(null, 'images');
  },
  filename: (req, file, cb) => {
    cb(null, new Date().toISOString() + '-' + file.originalname);
  }
});

// pass to the multer middleware to save the image first
app.use(
  multer({ storage: fileStorage, fileFilter: fileFilter }).single('image')
);

// serve the static file 
app.use('/images', express.static(path.join(__dirname, 'images')));

app.post("/image", (req,res,next) => {
  const title = req.body.title;
  // handle the file data which is returned from multer middleware
  const image = req.file;
  const imageUrl = image.path;
  // ...
});

Download

app.get("/download", (req,res,next) =>{
     const invoiceName = 'invoice-' + orderId + '.pdf';
     const invoicePath = path.join('data', 'invoices', invoiceName);
     // create stream to get file chunk data one by one
     const file = fs.createReadStream(invoicePath);
     
     res.setHeader('Content-Type', 'application/pdf');
     // to notify the browser that it is used to download file with specific name
     // to show save as dialog
      res.setHeader(
        'Content-Disposition',
        'attachment; filename="' + invoiceName + '"'
      );
     // res itself is a writeable stream, and forward the chunks of data 
     // from read stream, finally the all the buffers will be concat 
     // and form the final file on the browser
     file.pipe(res);
})

Deployment

Pre-action

  • Get the ubuntu server from Vultr / DigitalOcean / AWS

  • Change Password :sudo passwd

  • Install nodejs and update its version:

curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash -
sudo apt-get install -y nodejs
  • Install mysql :

sudo apt-get update
sudo apt-get install mysql-server
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'your-password';
  • Install forever / pm2

npm install -g forever

Https

  • Register the domain in goDaddy or other

  • Link to your ip address

  • Add Certbot PPA

sudo apt-get update &&
sudo apt-get install software-properties-common &&
sudo add-apt-repository universe &&
sudo add-apt-repository ppa:certbot/certbot &&
sudo apt-get update
  • Install Certbot

sudo apt-get install certbot
  • Register to obtain the key, cert and ca

sudo certbot certonly --standalone
  • Read the key ,cert and ca into server.js in production and be https

const https = require("https");
const fs = require("fs");
const IS_PROD = process.env.NODE_ENV === "production";
const http = require("http");
if (IS_PROD) {
  server = https.createServer(
    {
      key: fs.readFileSync(
        "/etc/letsencrypt/live/friendchats.xyz/privkey.pem",
        "utf8"
      ),
      cert: fs.readFileSync(
        "/etc/letsencrypt/live/friendchats.xyz/cert.pem",
        "utf8"
      ),
      ca: fs.readFileSync(
        "/etc/letsencrypt/live/friendchats.xyz/chain.pem",
        "utf8"
      ),
    },
    app
  );
} else {
  server = http.createServer(app);
}

server.listen(process.env.PORT, function () {
  console.log("Server Start ");
});

Forever

  • Install forever to execute the nodejs express program

npm install forever -g 
  • Execute npm command by using forever

forever start -c "npm run start:prod" ./
  • Find the uid by using:

forever list
  • Stop the program by using uid

forever stop {uid}
  • Find the uid who is using the port (e.g 8080)

lsof -i :8080
  • Kill the process by using uid

kill -9 uid