ExpressJS: Static and Dynamic Routes
Tags: express, node, tutorial, beginners
Published: 2020-04-26 04:26:29

Recently I've been writing simple VueJS tutorials. This got me thinking -- wouldn't it be better if I also had a backend that complements Vue? Several articles later, I was convinced that ExpressJS is just what I need.

This tutorial:
- **will** generate a bare-bones ExpressJS server app
- **will** discuss how to write a simple ExpressJS API (GET)
- **will** demonstrate how to convert a static route to a dynamic one
- **will not** discuss the complete RESTful verbs (POST, PUT, PATCH, etc)

## Project Setup
```bash
mkdir express-routing-practice && cd express-routing-practice
npm init -y
npm i --save express debug http
```
This will generate `package.json` and `package-json.lock` for us. We'll need the `debug` and `http` modules because it's required by `bin/www` (more details later).

#### Express Setup
For this tutorial, I don't recommend using the [Express generator](https://expressjs.com/en/starter/generator.html) because it creates a lot of boilerplate code that we won't use. What we'll do is use it as a guide to bootstrap our app. This also helps identify which sections of the Express generator is directly related to routing.

Create a `bin` folder and an empty file `www`.
```bash
mkdir bin && cd $_
touch www
```
Copy [this](https://github.com/expressjs/generator/blob/d07ce53595086dd07efb100279a7b7addc059418/templates/js/www) from the official repo to `bin/www` to do the heavy lifting. We don't need to delve in detail what each line does. However we do need to note that `var app = require('../app')` tells us which file is our entry point. Let's create that file now via `touch app.js` in the root folder, then add the following:
```javascript
// app.js
var express = require('express');
var app = express();

module.exports = app;
```
Update `package.json` to remove the default entry point `index.js` and add a new script to start our server:
```json
// before
{
  "name": "express-routing-practice",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
...
}

// after
{
  "name": "express-routing-practice",
  "version": "1.0.0",
  "description": "",
  "scripts": {
    "start": "DEBUG=express-routing-practice:* node ./bin/www",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
...
}
```
Then in your terminal, start your server via `npm start`. Visit `localhost:3000` in your browser. If you're seeing `Cannot GET /`, that means our server is operational! :tada:

## Create a GET endpoint
We'll create 2 routes with 1 GET endpoint for each. Create a new folder and the 2 files via:
```bash
mkdir routes
touch routes/home.js
touch routes/users.js
```
#### home route
Open `home.js` and paste the following:
```javascript
var express = require('express');
var router = express.Router();

// Explanation: A nameless path GET request without any parameters.
// We'll learn how to name a path in users route.
router.get('/', function(req, res, next) {
  return res.json({ message: 'Home!', data: null })
});

module.exports = router;
```
Then add this to `app.js` anywhere before `module.exports = app;` to use it:
```javascript
// Explanation: requests to `localhost:3000/` should be redirected to `routes/home.js`
var homeRouter = require('./routes/home')
app.use('/', homeRouter);
```

Restart your server then visit `localhost:3000` to see the json on screen!

#### users route
Setup `users.js` and add some data:
```javascript
var express = require('express');
var router = express.Router();

var data = [
  {
    name: 'Bibi',
  },
  {
    name: 'Colt',
  },
  {
    name: 'Jessie',
  }
]

router.get('/', function(req, res, next) {
  return res.json({ message: 'Users Index', data: data });
});

module.exports = router;
```
then update `app.js` to include:
```javascript
var usersRouter = require('./routes/users');
app.use('/users', usersRouter);
```
Restart server, visit 'localhost:3000/users' and see the data come to life.
**Tip: You can also use `cURL` to test your endpoints. We're making an API after all :smile:.**

#### Adding path name to a GET endpoint
By convention, a GET endpoint will return a complete list (or an index) of a resource. But should you need to set another GET endpoint, Express is ready for that.
Let's build on top of `users.js` to create more GET endpoints:
```javascript
router.get('/Bibi', function(req, res, next) {
  var name = req.originalUrl.split('/')[2];
  var user = data.filter(u => u.name == name);
  return res.json({ message: 'User Show', data: user });
});

router.get('/Colt', function(req, res, next) {
  var name = req.originalUrl.split('/')[2];
  var user = data.filter(u => u.name == name);
  return res.json({ message: 'User Show', data: user });
});

router.get('/Jessie', function(req, res, next) {
  var name = req.originalUrl.split('/')[2];
  var user = data.filter(u => u.name == name);
  return res.json({ message: 'User Show', data: user });
});
```
Explanation: a GET request to `localhost:3000/users/Bibi` will be redirected to the subpath `Bibi`, and so on.

Whoa there! Our reference data didn't change but our source code just scaled in size! Imagine if we had 99 objects in the `data` array -- will we make 99 subpaths? Well technically we *can* but wouldn't it be better if there was a way to encapsulate all these subpaths?

#### Dynamic routes
What we've created up until now are called static routes. To convert these into a dynamic route, we simply need to declare an identifier using a colon (`:`). Express then automagically determines which subpath the request should be redirected to.
Updating the three subpaths:
```javascript
router.get('/:name', function(req, res, next) {
  var name = req.params.name;
  var user = data.filter(u => u.name == name );
  return res.json({ message: 'Users Show', data: user });
});
```
Hooray! Now you'll be able to access `localhost:3000/users/Bibi`, `localhost:3000/users/Colt`, and `localhost:3000/users/Jessie` using one dynamic route :tada:!