Module 0336: Enabling async Express+node

Tak Auyeung, Ph.D.

October 10, 2021

Contents

 1 About this module
 2 A simple base script
  2.1 Enabling the use of ’async’ handlers
  2.2 Testing an async handler

1 About this module

2 A simple base script

Let us consider the following basic Express+node script.

Listing 1:A simple Express+node scripte
 
"use strict"; 
module.paths.unshift(’/usr/lib/node_modules’) 
const fs = require(’fs’) // module to handle file system 
const https = require(’https’) // module to handle HTTPS  as a protocol 
const express = require(’express’) // module to handle express framework 
const app = express() // an express instance 
// the following line gets the private key needed for SSL 
const privateKey = fs.readFileSync(’/var/local/ssl/selfsigned.key’,’utf8’) 
// the following line gets the certificate needed for SSL 
const certificate = fs.readFileSync(’/var/local/ssl/selfsigned.crt’,’utf8’) 
// the following line gets the port number Express listens to 
const portNumber = fs.readFileSync(’.port’,’utf8’).trim() 
// specify end points and handlers for each end point 
// 
function epRootHandler(req, res) 

  res.write("<h1>Hello, World! (from Tak for debugging)</h1>") 
  res.end() 

 
app.get(’/’, epRootHandler) 
 
// an object needed to create the HTTPS server 
const credentials = { key: privateKey, cert: certificate } 
// create the HTTPS server 
let httpsServer = https.createServer(credentials, app) 
// start the server 
httpsServer.listen(portNumber)

(You can download this script..)

Normally, the handler of an end-point (epRootHandler) cannot be an async function due to how the Express framework was written. However, by using the express-async-handler node module, one can now specify async end point handlers. The following shows the previous script, but with minimal changes to enable the use of async end-point handlers.

2.1 Enabling the use of ’async’ handlers

Listing 2:A simple Express+node script that is ’async’ enabled
 
"use strict"; 
module.paths.unshift(’/usr/lib/node_modules’) 
const fs = require(’fs’) // module to handle file system 
const https = require(’https’) // module to handle HTTPS  as a protocol 
const express = require(’express’) // module to handle express framework 
const asyncHandler = require(’express-async-handler’) 
const app = express() // an express instance 
// the following line gets the private key needed for SSL 
const privateKey = fs.readFileSync(’/var/local/ssl/selfsigned.key’,’utf8’) 
// the following line gets the certificate needed for SSL 
const certificate = fs.readFileSync(’/var/local/ssl/selfsigned.crt’,’utf8’) 
// the following line gets the port number Express listens to 
const portNumber = fs.readFileSync(’.port’,’utf8’).trim() 
// specify end points and handlers for each end point 
// 
async function epRootHandler(req, res) 

  res.write("<h1>Hello, World! (from Tak for debugging)</h1>") 
  res.end() 

 
app.get(’/’, asyncHandler(epRootHandler)) 
 
// an object needed to create the HTTPS server 
const credentials = { key: privateKey, cert: certificate } 
// create the HTTPS server 
let httpsServer = https.createServer(credentials, app) 
// start the server 
httpsServer.listen(portNumber)

(You can download this script.)

Note that const asyncHandler = require(’express-async-handler’) brings the module in.

Furthermore, asyncHandler is a wrapper that makes it possible to use an async handler as an end-point handler.

Despite the enabling of using async handlers, this new script behaves exactly the same as the previous one.

2.2 Testing an async handler

The following "prankster" script makes use of using await inside the async end-point handler to delay the response by 5 seconds.

Listing 3:A simple Express+node script that is ’async’ enabled and using await
 
"use strict"; 
module.paths.unshift(’/usr/lib/node_modules’) 
const fs = require(’fs’) // module to handle file system 
const https = require(’https’) // module to handle HTTPS  as a protocol 
const express = require(’express’) // module to handle express framework 
const asyncHandler = require(’express-async-handler’) 
const app = express() // an express instance 
// the following line gets the private key needed for SSL 
const privateKey = fs.readFileSync(’/var/local/ssl/selfsigned.key’,’utf8’) 
// the following line gets the certificate needed for SSL 
const certificate = fs.readFileSync(’/var/local/ssl/selfsigned.crt’,’utf8’) 
// the following line gets the port number Express listens to 
const portNumber = fs.readFileSync(’.port’,’utf8’).trim() 
// specify end points and handlers for each end point 
// 
async function delay(ms, value=undefined) 

  return new Promise( 
    (resolve, reject) => 
    { 
      setTimeout( 
        () => { resolve(value) }, ms 
      ) 
    } 
  ) 

 
async function epRootHandler(req, res) 

  await delay(3000) 
  res.write("<h1>Got you sweating!</h1>") 
  res.end() 

 
app.get(’/’, asyncHandler(epRootHandler)) 
 
// an object needed to create the HTTPS server 
const credentials = { key: privateKey, cert: certificate } 
// create the HTTPS server 
let httpsServer = https.createServer(credentials, app) 
// start the server 
httpsServer.listen(portNumber)

(You can download this script.)

Note that the async function delay is written using anonymous functions to make it more concise. The delay function is not our focus here, however.

The way epRootHandler utilizes await is of interest here. In reality, there are few reasons why a server may want to delay a response. However, there are many situations where a Express+node script may need to perform a lengthy asynchronous operations.

Lengthy asynchronous operations include querying a database, using RESTful API to query another server, performing a lengthy file operations, and etc. If node modules provide async APIs to these oeprations, then it becomes a simple matter to use await in a Express end-point handler.