Request and Response in Express.js

In Express.js, Request and Response objects are the core of the framework's ability to handle HTTP interactions. Understanding these objects is crucial for building robust, efficient, and scalable web applications. This chapter will guide you from the very basics to more advanced concepts of handling requests and responses in Express.js. By the end, you'll have a deep understanding of how to use these objects effectively.

What is the Request Object?

The Request object (req) in Express.js represents the HTTP request and contains properties for the request query string, parameters, body, HTTP headers, and more. This object provides all the information about the incoming HTTP request.

Basic Properties of the Request Object

Let’s explore the most common properties of the req object:

  • req.query: Contains the query parameters in the URL.
  • req.params: Contains route parameters.
  • req.body: Contains the body data of the request (usually in POST requests).
  • req.headers: Contains the headers sent by the client.
  • req.method: The HTTP method used (GET, POST, etc.).
  • req.url: The URL of the request.

Basic Example of Request Object

File: app.js

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

// Parse JSON bodies (as sent by API clients)
app.use(express.json());

// Basic route example
app.get('/user/:id', (req, res) => {
  console.log('Query Params:', req.query);
  console.log('Route Params:', req.params);
  console.log('Request Headers:', req.headers);
  console.log('Request Method:', req.method);
  console.log('Request URL:', req.url);

  res.send('Check your console!');
});

app.listen(port, () => {
  console.log(`Server running at http://localhost:${port}`);
});

				
			

Explanation:

  • req.query: Suppose you access http://localhost:3000/user/123?name=John, req.query will contain { name: 'John' }.
  • req.params: In the URL /user/:id, req.params will contain { id: '123' }.
  • req.headers: Contains all the headers sent by the client. For example, req.headers['user-agent'] might give you the browser’s user agent string.
  • req.method: Will return "GET" since the route is accessed via a GET request.
  • req.url: Will return the URL /user/123?name=John.

Output: When you access http://localhost:3000/user/123?name=John in your browser, the server console will output:

				
					Query Params: { name: 'John' }
Route Params: { id: '123' }
Request Headers: { ...headers... }
Request Method: GET
Request URL: /user/123?name=John

				
			

What is the Response Object?

The Response object (res) in Express.js represents the HTTP response that an Express app sends when it gets an HTTP request. This object provides methods to send responses in various formats like JSON, HTML, or plain text.

Basic Properties of the Response Object

Some of the most commonly used methods of the res object are:

  • res.send(): Sends a response of various types (text, HTML, JSON).
  • res.json(): Sends a JSON response.
  • res.status(): Sets the HTTP status for the response.
  • res.redirect(): Redirects the client to a different URL.
  • res.render(): Renders a view template.

Basic Example of Response Object

File: app.js

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

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

app.get('/json', (req, res) => {
  res.status(200).json({ message: 'Hello, JSON!' });
});

app.get('/redirect', (req, res) => {
  res.redirect('https://www.example.com');
});

app.listen(port, () => {
  console.log(`Server running at http://localhost:${port}`);
});

				
			

Explanation:

  • res.status(): Sets the HTTP status code. res.status(200) sets the status to 200 OK.
  • res.send(): Sends a string response. In this case, "Hello, World!".
  • res.json(): Sends a JSON response. The res.json() method automatically sets the Content-Type to application/json.
  • res.redirect(): Redirects the client to https://www.example.com.

Output:

  • Accessing http://localhost:3000/ will display "Hello, World!".
  • Accessing http://localhost:3000/json will return {"message":"Hello, JSON!"}.
  • Accessing http://localhost:3000/redirect will redirect you to https://www.example.com.

Handling Different HTTP Methods

Express.js allows handling of different HTTP methods like GET, POST, PUT, DELETE, etc. Each method corresponds to a different kind of request, commonly used in RESTful APIs.

Handling GET Requests

GET requests are typically used to retrieve data from the server.

File: app.js

				
					app.get('/user/:id', (req, res) => {
  const userId = req.params.id;
  res.send(`User ID: ${userId}`);
});

				
			

Explanation:

  • app.get(): Handles GET requests. The userId is extracted from the URL and sent back as a response.

Handling POST Requests

POST requests are used to send data to the server, often to create a new resource.

File: app.js

				
					app.post('/user', (req, res) => {
  const user = req.body;
  res.status(201).json({
    message: 'User created',
    user: user
  });
});

				
			

Explanation:

  • app.post(): Handles POST requests. The data sent in the request body (req.body) is used to create a new user. The status 201 Created is returned along with the user data.

Example Request:

				
					POST /user
Content-Type: application/json

{
  "name": "Jane Doe",
  "email": "jane@example.com"
}

				
			
				
					{
  "message": "User created",
  "user": {
    "name": "Jane Doe",
    "email": "jane@example.com"
  }
}

				
			

Handling PUT Requests

PUT requests are used to update an existing resource.

File: app.js

				
					app.put('/user/:id', (req, res) => {
  const userId = req.params.id;
  const updatedUser = req.body;
  
  res.status(200).json({
    message: `User ${userId} updated`,
    user: updatedUser
  });
});

				
			

Explanation:

  • app.put(): Handles PUT requests. The user ID from the URL and the updated user data from the request body are sent back as a response.

Handling DELETE Requests

DELETE requests are used to delete a resource.

File: app.js

				
					app.delete('/user/:id', (req, res) => {
  const userId = req.params.id;
  
  res.status(200).json({
    message: `User ${userId} deleted`
  });
});

				
			

Explanation:

  • app.delete(): Handles DELETE requests. The user ID from the URL is used to acknowledge the deletion.

Middleware and Request-Response Cycle

Middleware functions in Express.js are functions that have access to the req and res objects and can modify them or perform operations before passing control to the next middleware function in the stack

Creating Middleware

File: app.js

				
					// Logger Middleware
app.use((req, res, next) => {
  console.log(`${req.method} request for '${req.url}'`);
  next();
});

app.get('/', (req, res) => {
  res.send('Middleware example');
});

app.listen(port, () => {
  console.log(`Server running at http://localhost:${port}`);
});

				
			

Explanation:

  • app.use(): Adds a middleware function that logs the HTTP method and URL of each request.
  • next(): Passes control to the next middleware function. If not called, the request will be left hanging.

Output: Accessing any route logs the request method and URL to the console.

Using Middleware for Request Processing

Middleware can be used to process data before it reaches your route handler.

File: app.js

				
					app.use(express.json()); // Parses JSON body content

app.post('/user', (req, res, next) => {
  if (!req.body.name || !req.body.email) {
    return res.status(400).send('Missing required fields');
  }
  next();
});

app.post('/user', (req, res) => {
  const user = req.body;
  res.status(201).json({
    message: 'User created',
    user: user
  });
});

				
			

Explanation:

  • The first middleware parses JSON content in the request body.
  • The second middleware checks for required fields and sends a 400 Bad Request status if they are missing.

Advanced Concepts

Streaming Responses

Sometimes, you might need to stream data to the client instead of sending it all at once. Express supports streaming using the res object.

File: app.js

				
					app.get('/stream', (req, res) => {
  res.set('Content-Type', 'text/plain');
  
  const interval = setInterval(() => {
    res.write(`Current time: ${new Date().toLocaleTimeString()}\n`);
  }, 1000);
  
  setTimeout(() => {
    clearInterval(interval);
    res.end('Streaming ended.');
  }, 5000);
});

				
			

Explanation:

  • res.write(): Streams data to the client in chunks.
  • res.end(): Ends the response after 5 seconds.

Output: Accessing http://localhost:3000/stream will stream the current time to the client every second for 5 seconds.

Sending Files

Express makes it easy to send files as responses.

File: app.js

				
					const path = require('path');

app.get('/download', (req, res) => {
  const file = path.join(__dirname, 'sample.txt');
  res.download(file, (err) => {
    if (err) {
      res.status(500).send('File download failed');
    }
  });
});

				
			

Explanation:

  • res.download(): Sends a file for download. You can specify the path to the file and an optional callback to handle errors.

Error Handling

Express provides a simple yet powerful mechanism for handling errors in your application.

Basic Error Handling

File: app.js

				
					app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).send('Something broke!');
});

				
			

Explanation:

  • Error-handling middleware: In Express, the error-handling middleware must be defined last. It catches errors passed down from previous middleware or route handlers.

Catching 404 Errors

To handle routes that don’t exist, you can use middleware to catch 404 Not Found errors.

File: app.js

				
					app.use((req, res, next) => {
  res.status(404).send('Sorry, we couldn\'t find that!');
});

				
			

Explanation:

  • This middleware catches all requests that don’t match any route and returns a 404 Not Found response.

The Request and Response objects in Express.js are the backbone of any Express application. They allow you to handle incoming data, process it, and send appropriate responses back to the client. Whether you’re building simple applications or complex RESTful APIs, mastering these objects is crucial. With the detailed understanding provided in this chapter, you should be able to handle requests and responses in Express.js with confidence. Happy coding !❤️

Table of Contents