Express Fundamentals (minus the jargon)

Aug 4, 2020


This post answers the following questions with respect to Express:

  • What problem does Express solve?
  • Why does it exist?
  • When to use it?
  • What is it good for?

The goal is understand Express minus all the jargon & buzzwords.

Let's talk a bit about Node

Before talking about Express, let's look at some Node fundamentals.

Node allows us to run JavaScript outside of a browser. This matters because with this, we can use JavaScript to do the kind of things we do with Java, Python, etc. So, what Node provides us is a runtime for JavaScript. This has been achieved by porting Chrome browser's V8 JavaScript engine to Node.

Node also comes with an HTTP library. As a result, with Node, we can execute JavaScript on the server-side to serve HTTP requests. This means that the JavaScript we write can be execute on the client-side (browser) as well as server-side (node). This has huge implications because it allows us to write JavaScript code to handle experience on the browser-side & client requests on the server-side.

But, what has that got to do with Express? Let's look at the problem Express solves to understand that.

What problem does Express solve?

Express simplifies writing an HTTP server in Node. While Node has it's own http module, writing an HTTP server in Node (with this built-in module) can be cumbersome.

To understand the challenges, below is a code snippet of a simple HTTP server written with Node's http module to serve a single HTML file:

const http = require("http");         //Node's http library
const fs = require('fs').promises;    //Node's file system library (to read local files)

const host = ‘localhost’; const port = 8000;

//Every request we want Node to handle shall be managed const requestListener = function (req, res) {
fs.readFile(__dirname + “/index.html”) //Perform file I/O .then(contents => { res.setHeader(“Content-Type”, “text/html”); //Set HTTP response headers res.writeHead(200); //Set HTTP response headers res.end(contents); }) .catch(err => { //Perform error handling res.writeHead(500); res.end(err); return; }); }; const server = http.createServer(requestListener); server.listen(port, host, () => { console.log(Server is running on http://${host}:${port}); });

If you wish to run the above snippet:

  • Create a folder and an HTML file index.html within it (with some plain HTML content).
  • Then create a JavaScript file index-node.js within the same folder with above code.
  • Run the above code as node index-node.js and fire the URL http://localhost:8000 on the browser.

The code above can quickly become difficult to maintain when the server needs to serve many URLs & different file types (images, javascript, CSS, json, etc).

Now, contrast the above code with the below snippet. It does the same thing (an HTTP server that returns a single HTML file) using Express:

const express = require('express')
const app = express()
const port = 8000

app.get('/', function (req, res) { res.sendFile(__dirname + “/index.html”); })

app.listen(port, () => { console.log(Server is running on http://localhost:${port}) })

To run the above snippet:

  • Create a folder and an HTML file index.html within in.
  • Install express via npm install express
  • Then create a JavaScript file index-express.js within the same folder with above code.
  • Run the above code as node index-node.js and fire the URL http://localhost:8000 on the browser.

Handling HTTP response headers is absent in the above snippet because Express automatically handles that for us. So, express enables us to write maintainable server-side code when we want Node to serve requests for our web app.

Express enables us to write maintainable server-side code when we want Node as our web app server.

What makes Express stand out?

There are many libraries or frameworks to develop web applications on top of Node. But, Express is easily the most popular. This is because Express has minimal in-built functionality yet extensive libraries on top of it. Let's understand how this makes Express very effective for web development.

How is Express minimalist & what does that mean for development?

The core Express library helps us write request handlers for our web app servers. It does not enforce any rules, frameworks or design-patterns beyond this. We may connect to the database any-how or render a view as we prefer. This flexibility makes Express suitable for a wide-variety of web-apps without ever coming in the way of development.

The minimal in-built functionality also keeps Express very light-weight and fast.

How the libraries built on Express make it powerful?

Despite the minimal in-built functionality, Express can serve specific use-cases through libraries built on top of it. Infact, Express allows us to glue together multiple libraries to handle our specific requirements.

Below code-snippet demonstrates how the gluing together works to solve specific requirements. This snippet serves the request http://localhost:8000/getbookslist:

  • With a gzip compressed JSON
  • After performing HTTP authentication

Notice how the libraries express-basic-auth and compression are used to provide respective functionalities:

const express = require('express');
const basicAuth = require('express-basic-auth');		//library to enable basic HTTP auth
const compression = require('compression');				//library to enable gzip compression

const app = express() const port = 8000

app.use(basicAuth({ //tell express to authenticate requests users: { ‘librarian’: ‘supersecret’ }, challenge: true })); app.use(compression()); //tell express to compress responses

const booksList = [{name: ‘Book one’, author: ‘Author one’}, {name: ‘Book two’, author: ‘Author two’}];

app.get('/getbookslist’, function (req, res) { res.json(booksList); //return json as response })

app.listen(port, () => { console.log(Example app listening at http://localhost:${port}) })

To run the above snippet:

  • Create a folder and a file node-express-libraries.js within it.
  • Copy the above code into the file
  • Install libraries via command npm install express express-basic-auth compression
  • Run the above via node node-express-libraries.js
  • Fire the url http://localhost:8000/getbookslist in the browser and provide authentication details librarian/supersecret to see the JSON response.

The combination of minimal in-built functionality and extensive libraries that can be glued together to serve specific use-cases make Express very effective.

When to use Express?

If you are using Node to serve requests for your web app, you should use Express on top of it. So, any situation that is fit to use Node as the web app server should generally suit to use Express.

Why isn't Express part of Node itself?

The sections above may lead to an impression that Express should be used whenever Node is in use. This may lead to a question as to why isn't Express part of Node itself?

This isn't ideal because Node has capabilities beyond serving regular web apps. Node is commonly used as a server for situations where a persistent socket connection between the browser & server is needed (such as chat-based applications, online games, etc). Express may not fit such use-cases.

Conclusion

Express comes with minimal functionality to handle requests for web app servers. This makes it fast & flexible. This also ensures that it never comes in the way of development (about the choice of design pattern, folder structure, etc). At the same time, we can glue together multiple Express libraries to solve specific requirements. This combination of minimalism & flexibility makes Express very effective.


Punit Sethi

About the Author

Punit Sethi has been working with large e-Commerce & B2C websites on improving their site speed, scalability and frontend architecture. He tweets on these topics here.