Express.js
Background
JavaScript has long been the standard for developing web frontends. Historically, backends have looked much different than the frontends they complement, often implemented in distinct languages. Switching languages between writing two parts of the same component often risks confusion and inconsistency. One modern solution is to build your backend in JavaScript as well. Node.js is a cross-platform environment that can accommodate this. Programmers can rapidly develop robust, fully-functional apps by carefully utilizing open-source packages downloaded from the npm package manager.
What is Express.js?
Express.js is the most popular backend framework on npm, with over 28 million downloads in the week before HackUTD IX. It is a minimalist framework that provides a set of utility methods commonly needed by servers. We write our app-specific functions as a series of middleware for Express, using any additional libraries as required.
Getting Started
Let's create a backend API! We will use StackBlitz, an online IDE, for hassle-free development and testing. To get started, create a new Backend Express project in StackBlitz.
Understanding the Files
package.json
specifies how to install and run the project.
index.js
is the default entry point specified in package.json
.
Let's examine index.js
and modify it as needed.
Imports
const express = require('express');
const path = require('path');
const bodyParser = require('body-parser');
We import three libraries that we will use later on.
- Express.js: To support our backend
- Path: To load our frontend
- Body Parser: To make a JSON interface
Add the line for importing the body-parser
library to your index.js
file.
Similarly, you may import additional libraries as required. Explore npm to find libraries that can simplify your task.
Port
const port = 3010;
This defines the port
number our app will use on the network. If this port is taken, try another empty one.
App Initialization
const app = express();
We initialize an instance of Express and provide it an alias app
. We can now extend this app
to perform our desired functionality through a series of middleware.
Parser
app.use(bodyParser.json());
Add this line after app
initialization.
We want our API to send and receive data in JSON format. We don't want to write a JSON parser ourselves, so we are using a middleware that we imported from the body-parser
library.
Goal: As an example, let's write an API for a message board that accepts dad jokes.
Storage
const store = ['Welcome to the Board! Send in your worst dad jokes.'];
Our backend would need some space to store the messages. For a real-world application, you would want to store your data in a database with permanent storage (see SQL, NoSQL, Firebase).
For now, add the above line to create a temporary store
in memory. Note, with the temporary approach, all your user messages will get deleted when you restart the server.
Accessor
app.get('/api/dad', (req, res) => {
res.status(200).json({ jokes: store });
});
We define a custom middleware to allow users to fetch a list of jokes from the server.
By using the get
method of the app
, we are asking the app to accept HTTP GET requests. The first argument '/api/dad'
tells the app
the URL that should serve this function. The third argument is the function to be performed.
The req
argument has information about the incoming Request, and the res
argument is a Response object that can be used to reply to the request.
status(200)
sets the HTTP Status of the response to OK.
json( { jokes: store } )
attaches a JSON object to the response. In this case, the returned JSON object has one field jokes
containing our entire store
list.
Mutator
app.post('/api/dad', (req, res) => {
const { newJoke } = req.body;
store.push(newJoke);
res.status(200).send();
});
Our next middleware uses the same URL as the accessor, but is executed when a HTTP POST is requested.
Here, we establish a contract for passing data to our API that frontends must adhere to. The input must be JSON-formatted and must at least contain a newJoke
field. You may enforce stricter security policies here.
We extract this newJoke
from the object and add it to our store. Then, we send an empty OK response.
Serve Frontend from Express.js
app.get('/', (req, res) => {
res.sendFile(path.resolve('pages/index.html'));
});
Listen for Incoming Connections
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`);
});
Note, that the order of middleware matters, so we first configured the parser, then defined API routes (that use the parser), and finally started listening for incoming connections (that use the API).
Further Reading
Next.js – A framework that combines backend and frontend
External Links
- Express Routing
- Express Examples
- Express Tutorial
- GraphQL - A query language for your API
- Koa - A new framework by the team behind Express