Skip to content

1. Routing

1. Routing in ExpressJS

The breakdown of Express.js routing examples for the most common HTTP methods:

πŸ“š Routing in Express.js – Examples

const express = require('express');
const app = express();
// To parse JSON bodies (from POST/PUT requests)
app.use(express.json());
/** 🏠 Home Route (GET) */
app.get('/', function(req, res) {
res.send('Welcome to the homepage!');
});
/** βž• Create Data (POST) */
app.post('/data', function(req, res) {
const newData = req.body; // get data from client
// logic to save newData...
res.send(`Received new data: ${JSON.stringify(newData)}`);
});
/** πŸ”„ Update Data (PUT) */
app.put('/data/:id', function(req, res) {
const id = req.params.id;
const updatedData = req.body;
// logic to update data with id...
res.send(`Updated data with ID ${id}: ${JSON.stringify(updatedData)}`);
});
/** ❌ Delete Data (DELETE) */
app.delete('/data/:id', function(req, res) {
const id = req.params.id;
// logic to delete data with id...
res.send(`Deleted data with ID ${id}`);
});
// Start the server
app.listen(3000, function() {
console.log('Server is listening on port 3000');
});

πŸ” Quick Summary

HTTP MethodRoutePurpose
GET/Read homepage
POST/dataCreate new data
PUT/data/:idUpdate data by ID
DELETE/data/:idDelete data by ID
app.use(express.json());

Without it, req.body will be undefined in a POST or PUT request that sends JSON.

🧠 Why?

Middleware like express.json() inspects the incoming request and parses the body into a usable JavaScript object, attaching it to req.body.

2. Advance Routing

2.1 Route Parameters and Query Strings

Route parameters allow you to pass data via the URL itself. Query strings are often used for optional data that isn’t part of the URL path.

const express = require('express');
const app = express();
// Route with a parameter (e.g., /user/123)
app.get('/user/:id', (req, res) => {
const userId = req.params.id;
res.send(`User ID: ${userId}`);
});
// Route with a query string (e.g., /search?name=John)
app.get('/search', (req, res) => {
const name = req.query.name;
res.send(`Searching for: ${name}`);
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});

Explanation:

  • Route Parameters: In /user/:id, :id is a dynamic segment that can match any value. The req.params.id retrieves the value from the URL.

  • Query Strings: The route /search captures query strings like name=John. These are accessed via req.query.name.

2.2 Route Handling with Multiple HTTP Methods

Express allows you to handle the same route for different HTTP methods like GET, POST, PUT, DELETE.

const express = require('express');
const app = express();
// GET route
app.get('/profile', (req, res) => {
res.send('Viewing profile');
});
// POST route (for updating profile)
app.post('/profile', (req, res) => {
res.send('Profile updated');
});
// PUT route (for updating a specific part of the profile)
app.put('/profile', (req, res) => {
res.send('Profile completely updated');
});
// DELETE route (for deleting profile)
app.delete('/profile', (req, res) => {
res.send('Profile deleted');
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});

Explanation:

  • Each HTTP method (GET, POST, PUT, DELETE) corresponds to a different type of action on the /profile route.
  • GET is used to retrieve information, POST to create or update data, PUT to completely replace data, and DELETE to remove data.

2.3 Route Handling with Regular Expressions (Regex)

You can use regular expressions in route paths for more flexible matching.

const express = require('express');
const app = express();
// Match any route that starts with '/user/' followed by a number
app.get('/user/:id([0-9]+)', (req, res) => {
const userId = req.params.id;
res.send(`User ID (only numbers): ${userId}`);
});
// Match only routes with '/product/' followed by either 'apple' or 'banana'
app.get('/product/:name(apple|banana)', (req, res) => {
const productName = req.params.name;
res.send(`Product: ${productName}`);
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});

Explanation:

  • :id([0-9]+) uses a regular expression to match only numeric ids, preventing non-numeric IDs.
  • :name(apple|banana) restricts the value of :name to apple or banana, ensuring that other products are not matched.

2.4 Chained Route Handlers

You can chain multiple middleware or route handlers for a single route, making the code more modular.

Example:

const express = require('express');
const app = express();
// Middleware for logging
function logRequest(req, res, next) {
console.log(`Received ${req.method} request at ${req.url}`);
next();
}
// Middleware for user authentication
function checkAuth(req, res, next) {
const token = req.headers['authorization'];
if (token === 'valid-token') {
next(); // User is authenticated, proceed
} else {
res.status(401).send('Unauthorized');
}
}
// Route with multiple handlers
app.get('/profile', logRequest, checkAuth, (req, res) => {
res.send('Profile page for authenticated user');
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});

Explanation:

  • logRequest: Logs each request that reaches the /profile route.
  • checkAuth: Verifies if the request contains a valid authorization token.
  • Both middlewares are applied in a chain, and only if all pass, the final handler ((req, res) => { res.send('Profile page...')}) sends the response.

2.5 Route Grouping with express.Router()

To organize your routes more effectively, you can group them using the express.Router().

const express = require('express');
const app = express();
// Create a router for 'users' route group
const userRouter = express.Router();
// Define user-specific routes
userRouter.get('/:id', (req, res) => {
const userId = req.params.id;
res.send(`User profile for ID: ${userId}`);
});
userRouter.post('/', (req, res) => {
res.send('User created');
});
// Mount the router at '/users' path
app.use('/users', userRouter);
// General route for products
app.get('/products', (req, res) => {
res.send('Product list');
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});

Explanation:

  • express.Router(): This allows you to group routes into logical modules (like user-related routes in this example).
  • app.use('/users', userRouter) mounts the user-specific routes at the /users base path.
  • Route paths are relative to the /users path, so /users/:id will handle /users/123.

2.6 Dynamic Route Parameters

In more advanced scenarios, you might want to capture a dynamic route part and use it to match multiple patterns.

const express = require('express');
const app = express();
// Dynamic route that can accept different user types (admin, guest, member)
app.get('/profile/:userType(admin|guest|member)', (req, res) => {
const userType = req.params.userType;
res.send(`You are logged in as ${userType}`);
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});

Explanation:

  • :userType(admin|guest|member) matches one of the three types (admin, guest, member), and the handler retrieves that value from req.params.userType.
  • You can extend this to match different types of user routes or even dynamically fetch content based on the user type.

2.7 Catch-All Routes for 404 Error Handling

You can define a catch-all route for undefined routes and handle 404 errors.

const express = require('express');
const app = express();
// Your actual routes
app.get('/home', (req, res) => {
res.send('Home Page');
});
// Catch-all route for undefined routes
app.use((req, res) => {
res.status(404).send('Sorry, we could not find that route!');
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});

Explanation:

  • The app.use() without a path will match any route that is not already matched by previous routes.
  • It’s typically used to handle 404 errors or as a fallback handler.