Skip to main content
Node.js APIs Tutorial
CHAPTER 07 Beginner

Routing in Express.js

Updated: May 14, 2026
25 min read

# CHAPTER 7

Routing in Express.js

1. Introduction

A REST API requires dozens of endpoints. You need routes to fetch users, create posts, delete comments, and update profiles. If you write 50 different routes inside your main app.js file, your codebase will become an unreadable, 2,000-line disaster. In this chapter, we will master Express routing: defining different HTTP methods, capturing dynamic URL parameters, and organizing our routes cleanly using the Express Router.

2. Learning Objectives

By the end of this chapter, you will be able to:
  • Define distinct GET, POST, PUT, and DELETE routes.
  • Capture dynamic data from URLs using Route Parameters.
  • Extract query strings from the URL (e.g., ?sort=asc).
  • Modularize your code using express.Router().

3. Beginner-Friendly Explanation

Imagine a massive airport. Your app.js file is the main entrance. If every single passenger for every single flight tried to board their plane directly from the main entrance lobby, it would be pure chaos. Instead, airports use Terminals and Gates (Routing). When you enter the airport (app.js), signs direct you: "All Delta flights go to Terminal A" (const deltaRouter = require('./routes/delta')). "All American flights go to Terminal B." By dividing traffic into modular Terminals, the airport handles thousands of people effortlessly. Express Router does exactly this for your code.

4. Route Methods (CRUD)

Express makes it incredibly easy to define endpoints matching the REST HTTP verbs.
javascript
12345678910111213141516171819202122
const express = require('express');
const app = express();

// READ (GET)
app.get('/api/users', (req, res) => {
    res.json({ message: "Fetching all users" });
});

// CREATE (POST)
app.post('/api/users', (req, res) => {
    res.json({ message: "Creating a new user" });
});

// UPDATE (PUT)
app.put('/api/users', (req, res) => {
    res.json({ message: "Updating a user" });
});

// DELETE (DELETE)
app.delete('/api/users', (req, res) => {
    res.json({ message: "Deleting a user" });
});

5. Dynamic Route Parameters (req.params)

If you have 10,000 users, you cannot hardcode a route for /api/users/1 and /api/users/2. You use a dynamic placeholder with a colon :. Express captures the value and puts it in req.params.
javascript
12345678
// The ':id' acts as a wild-card placeholder
app.get('/api/users/:id', (req, res) => {
    
    // Extract the dynamic ID from the URL
    const userId = req.params.id; 
    
    res.json({ message: `Fetching data for User ID: ${userId}` });
});

*If a user visits /api/users/99, the API returns "Fetching data for User ID: 99".*

6. Query Strings (req.query)

Sometimes mobile apps send optional filters in the URL, like /api/users?sort=asc&role=admin. This is not a Route Parameter; it is a Query String. Express captures it in req.query.
javascript
123456
app.get('/api/search', (req, res) => {
    const sortBy = req.query.sort; // equals "asc"
    const role = req.query.role;   // equals "admin"
    
    res.json({ message: `Searching for ${role}s, sorted by ${sortBy}` });
});

7. Modular Routing (express.Router)

To keep app.js clean, we move all user-related routes into a separate file.

Step 1: Create routes/userRoutes.js

javascript
123456789101112
const express = require('express');
const router = express.Router(); // Create a mini-app

router.get('/', (req, res) => {
    res.json({ message: "All users" });
});

router.get('/:id', (req, res) => {
    res.json({ message: `User ${req.params.id}` });
});

module.exports = router; // Export the mini-app

Step 2: Connect it in app.js

javascript
12345678910
const express = require('express');
const app = express();

// Import the Router file
const userRoutes = require('./routes/userRoutes');

// Tell Express: "Any URL that starts with /api/users should be handled by userRoutes"
app.use('/api/users', userRoutes);

app.listen(3000);

*Now, app.js is perfectly clean, acting only as the main traffic director!*

8. Backend Workflow: Designing an API

When designing an API, write out your routes on paper first.
  • GET /api/posts (All posts)
  • POST /api/posts (Create post)
  • GET /api/posts/:id (One post)
  • GET /api/posts/:id/comments (Get comments for a specific post)

9. Best Practices

  • Route Ordering Matters: In Express, routes are evaluated top-to-bottom. If you define app.get('/api/users/:id') BEFORE app.get('/api/users/profile'), and someone visits /api/users/profile, Express will think the word "profile" is actually the dynamic :id! Always put specific static routes above dynamic wildcard routes.

10. Common Mistakes

  • Mixing up Params and Query: Beginners often try to access req.params.sort when the URL is ?sort=asc. Remember:
  • /users/5 -> Uses req.params.id
  • /users?id=5 -> Uses req.query.id

11. Exercises

  1. 1. Explain the architectural benefit of using express.Router() instead of defining all routes in app.js.

12. Coding Challenges

  • Challenge: Write a single Express route that captures both a dynamic route parameter and a query string. The URL format is /api/products/:category?limit=10. Extract both the category name and the limit number, and return them in a JSON response.

13. MCQs with Answers

Question 1

If a client visits the URL /api/employees/42, how do you extract the number 42 inside an Express route defined as app.get('/api/employees/:empId')?

Question 2

Which Express feature allows you to separate your routes into modular, dedicated files (like userRoutes.js) to keep your main app.js file clean?

14. Interview Questions

  • Q: Explain the difference between req.params and req.query. Give an example URL for each, demonstrating when a frontend developer would choose to use one over the other.
  • Q: Why is the physical top-to-bottom placement of route definitions critical in an Express application? What happens if a dynamic wildcard route is placed above a static route?

15. FAQs

Q: Can I put database logic directly inside the userRoutes.js file? A: You can, but you shouldn't. As your app grows, you should move the database logic into a "Controller" file (e.g., userController.js), and your Router file should just point to the Controller functions. We will build this exact MVC pattern in Chapter 10.

16. Summary

In Chapter 7, we mastered traffic management. By mapping RESTful HTTP verbs (GET, POST, PUT, DELETE) to specific routes, our API conforms to industry standards. We learned how to capture dynamic data directly from the URL path via req.params, and from optional filters via req.query. Finally, we utilized express.Router() to modularize our codebase, ensuring our application remains clean and maintainable as it scales.

17. Next Chapter Recommendation

Our API can read URL parameters, but how does it read a massive JSON payload (like a new user's password)? Proceed to Chapter 8: Handling Requests and Responses.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·