Most Frequently asked express Interview Questions

author image Hirely
at 02 Jan, 2025

Question: What is Express.js and why is it used in Node.js applications?

Answer:

Express.js is a lightweight, flexible, and fast web application framework for Node.js. It provides a robust set of features to build web and mobile applications, making it easier to handle routing, HTTP requests, middleware, and more.

Why it is used in Node.js applications:

  1. Simplifies HTTP Request Handling: Express simplifies the process of handling HTTP requests and responses, enabling developers to define routes for different HTTP methods (GET, POST, PUT, DELETE) with minimal code.

  2. Middleware Support: Express has built-in middleware support and allows developers to integrate custom middleware easily. Middleware functions in Express are executed during the request-response cycle and can perform tasks such as logging, authentication, and error handling.

  3. Routing Capabilities: Express enables routing of requests to different endpoints using simple, intuitive syntax. It supports dynamic route parameters and query strings, making it easier to handle complex request paths.

  4. Template Engine Integration: Express allows integration with template engines like EJS, Pug, or Handlebars, making it ideal for rendering dynamic HTML views.

  5. Asynchronous Programming: Express leverages Node.js’s non-blocking, event-driven nature, allowing developers to write asynchronous code that can handle multiple simultaneous requests efficiently.

  6. Extensibility: Express is highly extensible, enabling developers to add third-party libraries or custom functionality. It’s ideal for building RESTful APIs, single-page applications (SPAs), or full-stack applications.

  7. Minimalist Approach: Express provides only the essential functionality for building a web server, leaving developers free to choose additional libraries and tools as needed. This lightweight approach makes it ideal for building scalable and maintainable applications.

Express.js is widely used in Node.js applications because it streamlines the development process, reduces the amount of boilerplate code, and is designed to handle a variety of use cases, from simple APIs to complex web applications.

Question: How do you handle errors in an Express.js application?

Answer:

In Express.js, error handling is a crucial part of maintaining a robust application. Express provides a structured way to catch and handle errors using middleware. Below is a comprehensive overview of how to handle errors effectively:

  1. Error-Handling Middleware: Express allows you to define error-handling middleware that takes four arguments: err, req, res, and next. This middleware is used to handle any errors that occur during the request-response cycle.

    app.use((err, req, res, next) => {
      console.error(err.stack); // Log the error details
      res.status(500).send('Something went wrong!');
    });
    • The err parameter represents the error object.
    • The req and res are the standard request and response objects.
    • The next function is used to pass the error to the next middleware if necessary.
  2. Using try-catch for Asynchronous Errors: Express doesn’t automatically catch errors in asynchronous functions (e.g., those using async/await), so you must wrap asynchronous code in a try-catch block to catch any errors and forward them to the error-handling middleware.

    app.get('/example', async (req, res, next) => {
      try {
        // Code that may throw an error
        const result = await someAsyncFunction();
        res.send(result);
      } catch (err) {
        next(err); // Pass error to Express error handler
      }
    });
  3. Handling 404 Errors: To handle requests to undefined routes, you can define a 404 handler at the end of your routing middleware.

    app.use((req, res, next) => {
      res.status(404).send('Page Not Found');
    });
  4. Custom Error Classes: You can create custom error classes to provide more context about errors. For example, you can define a NotFoundError class:

    class NotFoundError extends Error {
      constructor(message) {
        super(message);
        this.name = 'NotFoundError';
        this.statusCode = 404;
      }
    }
    
    app.get('/error', (req, res, next) => {
      const error = new NotFoundError('The requested resource was not found.');
      next(error);
    });

    In the error-handling middleware, you can then access the custom error’s properties like statusCode and message.

    app.use((err, req, res, next) => {
      const statusCode = err.statusCode || 500;
      res.status(statusCode).send({ message: err.message });
    });
  5. Validation Errors: If you’re using libraries like Joi, express-validator, or celebrate to validate incoming data, errors are typically passed to the error-handling middleware. For example, using express-validator:

    const { body, validationResult } = require('express-validator');
    
    app.post('/submit', 
      body('email').isEmail().withMessage('Invalid email format'),
      (req, res, next) => {
        const errors = validationResult(req);
        if (!errors.isEmpty()) {
          const error = new Error('Validation Failed');
          error.statusCode = 400;
          error.details = errors.array();
          return next(error);
        }
        res.send('Success!');
      }
    );
  6. Logging Errors: It’s a good practice to log errors, especially in production, for better debugging and monitoring. You can use libraries like winston or morgan for logging errors and requests.

    const winston = require('winston');
    
    const logger = winston.createLogger({
      transports: [
        new winston.transports.Console(),
        new winston.transports.File({ filename: 'error.log', level: 'error' })
      ]
    });
    
    app.use((err, req, res, next) => {
      logger.error(err.message);
      res.status(500).send('An error occurred');
    });

Key Points:

  • Express provides error-handling middleware to catch and respond to errors.
  • Use try-catch blocks for asynchronous errors, and always pass the error to the next middleware using next(err).
  • Handle common errors like 404s with appropriate middleware.
  • You can use custom error classes for better error categorization.
  • Validation libraries can catch input errors and pass them to error-handling middleware.
  • Always log errors to keep track of issues, especially in production environments.

By effectively using these techniques, you can manage errors gracefully and provide users with meaningful error messages while also improving the maintainability of your Express.js application.

Question: What is middleware in Express.js? Can you give an example?

Answer:

Middleware in Express.js refers to functions that have access to the request (req), response (res), and next functions in the request-response cycle. These functions can perform tasks such as modifying the request and response objects, executing code, ending the request-response cycle, and calling the next middleware in the stack.

Middleware is used to:

  • Handle requests before reaching the route handler.
  • Perform logging, authentication, validation, error handling, etc.
  • Modify request or response objects or perform actions like parsing request bodies.

Types of Middleware in Express.js:

  1. Application-level Middleware: Middleware that is used globally across the application. It is defined by using app.use() or specific route methods like app.get(), app.post(), etc.

  2. Route-specific Middleware: Middleware that only applies to specific routes. It can be attached directly to routes.

  3. Built-in Middleware: Express has some built-in middleware like express.static() for serving static files, express.json() for parsing JSON request bodies, etc.

  4. Error-handling Middleware: Middleware that is specifically used for catching and handling errors, defined by having four arguments: err, req, res, and next.

Example of Middleware in Express.js:

Simple Middleware Example:

This middleware logs the request details (method, URL, and timestamp) for every incoming request:

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

// Simple middleware to log request details
app.use((req, res, next) => {
  console.log(`${req.method} ${req.url} at ${new Date()}`);
  next(); // Pass control to the next middleware or route handler
});

// Route handler
app.get('/', (req, res) => {
  res.send('Hello, World!');
});

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

In this example:

  • app.use() defines a middleware function that runs for every request.
  • The middleware logs the HTTP method, URL, and timestamp.
  • After logging, next() is called to pass control to the next middleware or route handler.

Middleware for Route Handling:

Middleware can also be applied to specific routes. For example, if you only want to log requests for the /login route:

app.post('/login', (req, res, next) => {
  console.log('Login attempt at:', new Date());
  next(); // Pass control to the next middleware or route handler
}, (req, res) => {
  res.send('Login Successful');
});

Here, the logging middleware only applies to the /login route.

Built-in Middleware Example:

Express provides built-in middleware to parse JSON data in incoming requests. For example, using express.json():

app.use(express.json()); // Built-in middleware to parse JSON body in requests

app.post('/data', (req, res) => {
  console.log(req.body); // The request body is now parsed as JSON
  res.send('Data received');
});

This example uses express.json() middleware to parse the JSON body in the request and make it available in req.body.

Error-handling Middleware Example:

Express provides a way to define error-handling middleware, which is typically placed at the end of all middleware and route definitions:

// A middleware that simulates an error
app.get('/error', (req, res, next) => {
  const error = new Error('Something went wrong!');
  error.status = 500;
  next(error); // Pass the error to the error-handling middleware
});

// Error-handling middleware (must be defined after all routes)
app.use((err, req, res, next) => {
  console.error(err.stack); // Log the error stack
  res.status(err.status || 500).send({ error: err.message });
});

In this example:

  • The route /error triggers an error.
  • The error is passed to the error-handling middleware using next(error).
  • The error-handling middleware logs the error and sends an appropriate response to the client.

Key Points about Middleware:

  • Order Matters: Middleware functions are executed in the order they are defined. The first middleware that matches a request is executed first.
  • next() Function: It is used to pass control to the next middleware or route handler. If next() is not called, the request will hang and not proceed to the next step.
  • Can Modify Requests/Responses: Middleware can modify the req and res objects, allowing for powerful functionality such as adding authentication headers or parsing request bodies.

Middleware is a fundamental concept in Express.js and is essential for building flexible, maintainable, and scalable applications.

Question: What are the different types of middleware in Express.js?

Answer:

In Express.js, middleware refers to functions that are executed during the request-response cycle. Middleware can be categorized into several types based on their scope and purpose. Here are the main types of middleware in Express.js:


1. Application-level Middleware

  • Definition: Middleware that is applied globally across the entire application.

  • Usage: Defined using app.use() or route-specific methods like app.get(), app.post(), etc.

  • Example:

    const express = require('express');
    const app = express();
    
    // Application-level middleware
    app.use((req, res, next) => {
      console.log('Request Time: ', Date.now());
      next(); // Pass control to the next middleware or route handler
    });
    
    app.get('/', (req, res) => {
      res.send('Hello World');
    });
    
    app.listen(3000);
  • Use Cases: Logging, CORS handling, static file serving, body parsing (JSON, URL encoded).


2. Router-level Middleware

  • Definition: Middleware that is applied only to specific routes or routers.

  • Usage: Defined using router.use() for a specific router or using route-specific methods.

  • Example:

    const express = require('express');
    const app = express();
    const router = express.Router();
    
    // Router-level middleware
    router.use((req, res, next) => {
      console.log('Router-level middleware triggered');
      next();
    });
    
    router.get('/', (req, res) => {
      res.send('Router Home');
    });
    
    app.use('/router', router); // Attach the router to a specific route
    
    app.listen(3000);
  • Use Cases: Grouping middleware for specific parts of an application or for certain routes.


3. Built-in Middleware

  • Definition: Middleware that comes pre-built with Express.js, designed to handle common tasks like parsing request bodies or serving static files.

  • Examples:

    • express.json(): Parses incoming requests with JSON payloads.
    • express.urlencoded(): Parses incoming requests with URL-encoded payloads.
    • express.static(): Serves static files like images, stylesheets, and JavaScript.
  • Example:

    const express = require('express');
    const app = express();
    
    // Built-in middleware to parse JSON request body
    app.use(express.json());
    
    // Built-in middleware to serve static files
    app.use(express.static('public'));
    
    app.post('/submit', (req, res) => {
      console.log(req.body); // The request body is parsed as JSON
      res.send('Data received');
    });
    
    app.listen(3000);
  • Use Cases: Body parsing, serving static assets, URL decoding.


4. Third-party Middleware

  • Definition: Middleware that is not part of Express but is created by third-party developers and often available through npm.

  • Examples:

    • morgan: HTTP request logger middleware.
    • cors: Cross-Origin Resource Sharing middleware to handle CORS.
    • helmet: Security-related middleware to set various HTTP headers.
    • body-parser: (Deprecated in favor of express.json() and express.urlencoded()) to parse request bodies.
  • Example:

    const express = require('express');
    const morgan = require('morgan');
    const app = express();
    
    // Third-party middleware to log HTTP requests
    app.use(morgan('dev'));
    
    app.get('/', (req, res) => {
      res.send('Hello, world!');
    });
    
    app.listen(3000);
  • Use Cases: Logging, CORS management, security enhancements, body parsing.


5. Error-handling Middleware

  • Definition: Middleware specifically designed to catch errors that occur during the request-response cycle. It takes four parameters: err, req, res, and next.

  • Usage: Defined after all other routes and middleware.

  • Example:

    const express = require('express');
    const app = express();
    
    // Example route that throws an error
    app.get('/error', (req, res, next) => {
      const err = new Error('Something went wrong!');
      next(err); // Pass the error to the error handler
    });
    
    // Error-handling middleware (must be defined last)
    app.use((err, req, res, next) => {
      console.error(err.stack); // Log the error stack
      res.status(500).send({ message: err.message }); // Send error response
    });
    
    app.listen(3000);
  • Use Cases: Handling exceptions, logging errors, sending appropriate responses (e.g., 404, 500 errors).


6. Custom Middleware

  • Definition: Middleware that you define for custom purposes, such as authentication, validation, or any other custom functionality.

  • Example:

    const express = require('express');
    const app = express();
    
    // Custom middleware for authentication
    app.use((req, res, next) => {
      if (req.headers['authorization'] !== 'Bearer my-token') {
        return res.status(403).send('Forbidden');
      }
      next(); // If authorized, pass to next middleware
    });
    
    app.get('/', (req, res) => {
      res.send('Hello, authenticated user!');
    });
    
    app.listen(3000);
  • Use Cases: Custom authentication, logging, custom response handling, etc.


Summary of Middleware Types:

  1. Application-level Middleware: Applies to all routes globally.
  2. Router-level Middleware: Applies only to specific routes or groups of routes.
  3. Built-in Middleware: Pre-packaged middleware for common tasks (e.g., express.json(), express.static()).
  4. Third-party Middleware: Middleware provided by third-party libraries (e.g., morgan, helmet, cors).
  5. Error-handling Middleware: Specialized middleware for catching and responding to errors.
  6. Custom Middleware: User-defined middleware for specific functionality.

Middleware is essential for handling tasks like request validation, error handling, security, logging, and more in Express.js applications. The flexibility of middleware allows for a highly customizable and modular approach to building web applications.

Read More

If you can’t get enough from this article, Aihirely has plenty more related information, such as express interview questions, express interview experiences, and details about various express job positions. Click here to check it out.

Trace Job opportunities

Hirely, your exclusive interview companion, empowers your competence and facilitates your interviews.

Get Started Now