Node.js Express Middleware Practice Questions with Solutions

Introductions

Express middleware is a function that runs between the incoming request and the final response. Middleware can log requests, check users, validate data, modify requests, handle errors, and perform many other tasks. In this chapter, you will practice Express middleware through 10 solved questions, starting with basic middleware and gradually moving to multiple middleware, route-specific middleware, built-in middleware, custom middleware, authentication checks, validation, and error-handling middleware. Node.js Express Middleware practice questions with solutions help to understand the concepts.

Question 1: How do you create basic middleware in Express.js?

Problem

Create middleware that prints a message whenever a request reaches the Express server.

Solution

const express = require("express");

const app = express();

app.use((req, res, next) => {

    console.log("Middleware executed.");

    next();

});

app.get("/", (req, res) => {

    res.send("Home Page");

});

app.listen(3000, () => {

    console.log(
        "Server running on http://localhost:3000"
    );

});

Run the Application

node index.js

Open:

http://localhost:3000

Browser Output

Home Page

Console Output

Middleware executed.

Step-by-Step Explanation

This is middleware:

(req, res, next) => {

    console.log("Middleware executed.");

    next();

}

The three important parameters are:

req
res
next

req contains information about the incoming request.

res is used to send a response.

next() tells Express to continue to the next middleware or route handler.

The middleware is registered using:

app.use(...)

Request Flow

Browser
   ↓
Middleware
   ↓
next()
   ↓
Route
   ↓
Response

Important Point

If middleware does not send a response, it normally needs to call next() so the request can continue.


Question 2: How do you create middleware that logs HTTP method and URL?

Problem

Create a logging middleware that displays the HTTP method and requested URL in the terminal.

Solution

const express = require("express");

const app = express();

app.use((req, res, next) => {

    console.log(
        `Method: ${req.method}`
    );

    console.log(
        `URL: ${req.url}`
    );

    next();

});

app.get("/", (req, res) => {

    res.send("Home Page");

});

app.get("/about", (req, res) => {

    res.send("About Page");

});

app.listen(3000, () => {

    console.log(
        "Server running on http://localhost:3000"
    );

});

Test

Open:

http://localhost:3000/

Console:

Method: GET
URL: /

Now open:

http://localhost:3000/about

Console:

Method: GET
URL: /about

Step-by-Step Explanation

The HTTP method is available through:

req.method

The requested URL is available through:

req.url

The middleware runs before both routes because:

app.use(...)

was placed before the routes.


Question 3: How do you use multiple middleware functions?

Problem

Create two middleware functions. The first should print a message, and the second should print another message before sending the response.

Solution

const express = require("express");

const app = express();

const firstMiddleware = (req, res, next) => {

    console.log("First middleware");

    next();

};

const secondMiddleware = (req, res, next) => {

    console.log("Second middleware");

    next();

};

app.get(
    "/",
    firstMiddleware,
    secondMiddleware,
    (req, res) => {

        res.send("Home Page");

    }
);

app.listen(3000, () => {

    console.log(
        "Server running on http://localhost:3000"
    );

});

Console Output

When you visit /:

First middleware
Second middleware

Step-by-Step Explanation

The request enters:

firstMiddleware

Then:

next();

passes control to:

secondMiddleware

Then its:

next();

passes control to the final route handler.

Request Flow

Request
   ↓
First Middleware
   ↓
next()
   ↓
Second Middleware
   ↓
next()
   ↓
Route Handler
   ↓
Response

Important Point

Middleware functions execute in the order in which they are registered.


Question 4: How do you create route-specific middleware?

Problem

Create an authentication middleware that runs only for the /dashboard route.

Solution

const express = require("express");

const app = express();

const checkLogin = (req, res, next) => {

    const loggedIn = true;

    if (!loggedIn) {

        return res.status(401).send(
            "Please login first."
        );

    }

    next();

};

app.get("/home", (req, res) => {

    res.send("Home Page");

});

app.get(
    "/dashboard",
    checkLogin,
    (req, res) => {

        res.send("Welcome to your Dashboard.");

    }
);

app.listen(3000, () => {

    console.log(
        "Server running on http://localhost:3000"
    );

});

Test

Open:

http://localhost:3000/dashboard

Output:

Welcome to your Dashboard.

Step-by-Step Explanation

The middleware is:

const checkLogin = (req, res, next) => {

The login status is temporarily represented by:

const loggedIn = true;

If the user is not logged in:

if (!loggedIn) {

the server sends:

return res.status(401).send(
    "Please login first."
);

Otherwise:

next();

allows the request to reach the dashboard.


Question 5: How do you use built-in JSON middleware?

Problem

Create a POST API that receives JSON data from the client.

Solution

const express = require("express");

const app = express();

app.use(express.json());

app.post("/students", (req, res) => {

    const name = req.body.name;
    const course = req.body.course;

    res.json({
        message: "Student received.",
        name: name,
        course: course
    });

});

app.listen(3000, () => {

    console.log(
        "Server running on http://localhost:3000"
    );

});

Send This JSON

{
    "name": "Rahul",
    "course": "Node.js"
}

Response

{
    "message": "Student received.",
    "name": "Rahul",
    "course": "Node.js"
}

Step-by-Step Explanation

This line enables JSON parsing:

app.use(express.json());

The incoming JSON can then be accessed through:

req.body

For example:

req.body.name

gets the name.

And:

req.body.course

gets the course.


Question 6: How do you create validation middleware?

Problem

Create middleware that checks whether name and email are present before creating a student.

Solution

const express = require("express");

const app = express();

app.use(express.json());

const validateStudent = (req, res, next) => {

    const {
        name,
        email
    } = req.body;

    if (!name || !email) {

        return res.status(400).json({
            success: false,
            message: "Name and email are required."
        });

    }

    next();

};

app.post(
    "/students",
    validateStudent,
    (req, res) => {

        res.status(201).json({
            success: true,
            message: "Student created.",
            student: req.body
        });

    }
);

app.listen(3000, () => {

    console.log(
        "Server running on http://localhost:3000"
    );

});

Valid Request

{
    "name": "Aman",
    "email": "aman@example.com"
}

Response

{
    "success": true,
    "message": "Student created.",
    "student": {
        "name": "Aman",
        "email": "aman@example.com"
    }
}

Invalid Request

{
    "name": "Aman"
}

Response

{
    "success": false,
    "message": "Name and email are required."
}

Step-by-Step Explanation

The middleware extracts:

const {
    name,
    email
} = req.body;

Then checks:

if (!name || !email)

If something is missing, the middleware sends a response and stops.

If everything is present:

next();

allows the request to continue.


Question 7: How do you modify the request object using middleware?

Problem

Create middleware that adds the current user’s name to the request object before the route runs.

Solution

const express = require("express");

const app = express();

const addUser = (req, res, next) => {

    req.user = {
        name: "Rahul",
        role: "student"
    };

    next();

};

app.get(
    "/profile",
    addUser,
    (req, res) => {

        res.json({
            message: "User profile",
            user: req.user
        });

    }
);

app.listen(3000, () => {

    console.log(
        "Server running on http://localhost:3000"
    );

});

Output

{
    "message": "User profile",
    "user": {
        "name": "Rahul",
        "role": "student"
    }
}

Step-by-Step Explanation

Middleware adds a new property:

req.user = {
    name: "Rahul",
    role: "student"
};

Then:

next();

passes the modified request to the route.

The route can now access:

req.user

Request Flow

Request
   ↓
addUser Middleware
   ↓
req.user added
   ↓
next()
   ↓
/profile Route
   ↓
Response

Important Point

Adding information to req is a common pattern when middleware needs to pass data to later middleware or route handlers.


Question 8: How do you create role-based middleware?

Problem

Allow only admin users to access an admin page.

Solution

const express = require("express");

const app = express();

const checkAdmin = (req, res, next) => {

    const user = {
        name: "Rahul",
        role: "student"
    };

    if (user.role !== "admin") {

        return res.status(403).json({
            success: false,
            message: "Access denied."
        });

    }

    next();

};

app.get(
    "/admin",
    checkAdmin,
    (req, res) => {

        res.send("Welcome Admin.");

    }
);

app.listen(3000, () => {

    console.log(
        "Server running on http://localhost:3000"
    );

});

Output

Because the user’s role is:

student

the server returns:

{
    "success": false,
    "message": "Access denied."
}

with status:

403 Forbidden

Step-by-Step Explanation

The middleware checks:

if (user.role !== "admin")

If the role is not admin, the request is stopped:

return res.status(403).json({
    success: false,
    message: "Access denied."
});

If the role is admin, the middleware would call:

next();

Question 9: How do you create error-handling middleware?

Problem

Create an Express application that catches an error and sends a JSON response.

Solution

const express = require("express");

const app = express();

app.get("/error", (req, res, next) => {

    const error = new Error(
        "Something went wrong."
    );

    next(error);

});

app.use((error, req, res, next) => {

    console.error(error.message);

    res.status(500).json({
        success: false,
        message: error.message
    });

});

app.listen(3000, () => {

    console.log(
        "Server running on http://localhost:3000"
    );

});

Test

Open:

http://localhost:3000/error

Output

{
    "success": false,
    "message": "Something went wrong."
}

Step-by-Step Explanation

The route creates an error:

const error = new Error(
    "Something went wrong."
);

Then passes it to Express:

next(error);

Because next() receives an error, Express looks for error-handling middleware.

The error middleware has four parameters:

(error, req, res, next)

This is important.

It sends:

res.status(500).json({
    success: false,
    message: error.message
});

Question 10: How do you combine multiple Express middleware types in one application?

Problem

Create a small Express application containing:

  • Global logging middleware
  • JSON middleware
  • User middleware
  • Validation middleware
  • Route-specific middleware
  • Error-handling middleware
  • A student API

Solution

const express = require("express");

const app = express();


// 1. Built-in JSON middleware

app.use(express.json());


// 2. Global logging middleware

app.use((req, res, next) => {

    console.log(
        `${req.method} ${req.url}`
    );

    next();

});


// 3. User middleware

const addUser = (req, res, next) => {

    req.user = {
        name: "Rahul",
        role: "student"
    };

    next();

};


// 4. Validation middleware

const validateStudent = (req, res, next) => {

    const {
        name,
        course
    } = req.body;

    if (!name || !course) {

        return res.status(400).json({
            success: false,
            message: "Name and course are required."
        });

    }

    next();

};


// 5. Student route

app.post(
    "/students",
    addUser,
    validateStudent,
    (req, res) => {

        res.status(201).json({
            success: true,
            message: "Student created successfully.",
            createdBy: req.user.name,
            student: {
                name: req.body.name,
                course: req.body.course
            }
        });

    }
);


// 6. Error route

app.get("/error", (req, res, next) => {

    next(
        new Error("Demo server error.")
    );

});


// 7. 404 middleware

app.use((req, res, next) => {

    const error = new Error(
        "Route not found."
    );

    error.statusCode = 404;

    next(error);

});


// 8. Error-handling middleware

app.use(
    (error, req, res, next) => {

        console.error(
            error.message
        );

        const statusCode =
            error.statusCode || 500;

        res.status(statusCode).json({
            success: false,
            message: error.message
        });

    }
);


// Start server

app.listen(3000, () => {

    console.log(
        "Server running on http://localhost:3000"
    );

});

Test the Application

Test 1: Create Student

Send:

POST /students

with:

{
    "name": "Aman",
    "course": "Node.js"
}

Response

{
    "success": true,
    "message": "Student created successfully.",
    "createdBy": "Rahul",
    "student": {
        "name": "Aman",
        "course": "Node.js"
    }
}

What Happened?

The request passed through:

express.json()
       ↓
Logging Middleware
       ↓
addUser
       ↓
validateStudent
       ↓
POST /students
       ↓
Response

Test 2: Send Invalid Data

Send:

{
    "name": "Aman"
}

The validation middleware detects that course is missing.

Response:

{
    "success": false,
    "message": "Name and course are required."
}

Test 3: Open an Unknown Route

Visit:

http://localhost:3000/hello

Response:

{
    "success": false,
    "message": "Route not found."
}

Test 4: Trigger an Error

Visit:

http://localhost:3000/error

Response:

{
    "success": false,
    "message": "Demo server error."
}

Step-by-Step Middleware Flow

The complete request flow looks like this:

Client Request
      ↓
express.json()
      ↓
Logging Middleware
      ↓
Route-Specific Middleware
      ↓
Validation Middleware
      ↓
Route Handler
      ↓
Response

If something goes wrong:

Error
  ↓
Error-Handling Middleware
  ↓
Error Response

Key Takeaways

  • Middleware is a function that runs during the Express request-response cycle.
  • Middleware can execute before a route handler.
  • Middleware normally receives req, res, and next.
  • req contains information about the incoming request.
  • res is used to send a response.
  • next() passes control to the next middleware or route handler.
  • app.use() is commonly used to register middleware.
  • Middleware executes in the order in which it is registered.
  • Multiple middleware functions can be used for one route.
  • Middleware can be global or route-specific.
  • Global middleware can affect many or all routes.
  • Route-specific middleware runs only for selected routes.
  • express.json() is built-in middleware for parsing JSON request bodies.
  • Middleware can validate incoming data.
  • Middleware can add information to the req object.
  • Authentication checks can be implemented as middleware.
  • Authorization and role checks can be implemented as middleware.
  • Middleware can stop a request by sending a response.
  • Middleware can pass an error to Express using next(error).
  • Error-handling middleware has four parameters: error, req, res, and next.
  • A 404 handler can be implemented using middleware.
  • Middleware helps keep application logic organized.
  • Validation middleware can prevent invalid data from reaching the main route.
  • Logging middleware can help monitor incoming requests.
  • Middleware is a core concept used in Express-based REST APIs.

FAQs

1. What is middleware in Express.js?

Middleware is a function that runs between the incoming request and the final response.

A basic middleware function looks like:

app.use((req, res, next) => {

    console.log("Middleware executed.");

    next();

});

It can perform tasks such as logging, authentication, validation, and request processing.

2. What does next() do in Express middleware?

next() tells Express to continue to the next middleware or route handler.

Example:

app.use((req, res, next) => {

    console.log("First middleware");

    next();

});

Without next(), the request may stop if the middleware does not send a response.

3. What is the difference between app.use() and route-specific middleware?

app.use() is commonly used to register middleware that can run for multiple routes.

Example:

app.use(loggingMiddleware);

Route-specific middleware is attached directly to a route:

app.get(
    "/admin",
    checkAdmin,
    (req, res) => {

        res.send("Admin Page");

    }
);

The second example runs checkAdmin only for the /admin route.

4. What is express.json() in Express.js?

express.json() is built-in Express middleware that parses incoming JSON request bodies.

Example:

app.use(express.json());

After enabling it, JSON data can be accessed through:

req.body

5. Can middleware modify req and res?

Yes. Middleware can add or modify properties on the request and response objects.

For example:

req.user = {
    name: "Rahul",
    role: "student"
};

A later route can access:

req.user

This pattern is commonly used to pass information from middleware to route handlers.

6. What is error-handling middleware in Express.js?

Error-handling middleware handles errors that occur during request processing.

It has four parameters:

(error, req, res, next)

Example:

app.use((error, req, res, next) => {

    res.status(500).json({
        message: error.message
    });

});

Express identifies it as error-handling middleware because of the four-parameter function signature.

7. Can multiple middleware functions be used on one Express route?

Yes. You can use multiple middleware functions on the same route.

Example:

app.post(
    "/students",
    authenticate,
    validateStudent,
    createStudent
);

The request moves through the middleware functions in order. Each middleware normally calls next() when it wants the request to continue.

Written by Shubhranshu Shekhar, who has trained 20000+ students in coding.

Scroll to Top