Login

Sign Up

Request Data: Query, Params, Body
Daksh Dixit

Posted on Aug 20, 2025 | Backend

Request Data: Query, Params, Body

Hey Devs!

Ever wonder how a website knows exactly which user profile to show you when you click a link? Or how it filters search results for "laptops" under "₹50,000"? Or how it processes your login information securely when you hit "Submit"? The answer lies in how data is sent from your browser (the client) to the server.

When a client communicates with a server, it doesn't just ask for a page; it often sends along extra information. This data is the lifeblood of dynamic web applications. In the world of Express.js, we have three primary ways to receive this data on the server: through the Query, Params, and Body of a request.

Today, we're going to demystify these three concepts, explore their advanced use cases, and show you how to handle the tricky edge cases you'll encounter in the real world.


Table of Contents
What is Request Data? An Analogy
Decoding req.query: The "?" in the URL
Decoding req.params: The Dynamic URL Segments
Decoding req.body: The Hidden Payload
When to Use Which? A Quick Comparison
A Practical Example: Building a Robust API
How to Test Your Routes (with Postman/ThunderClient)
Important Tips & Cautions

What is Request Data? An Analogy

At its core, request data is just information the client sends to the server to specify what it wants. Think of it like ordering at a coffee shop:

  1. Params (req.params): You tell the barista you want the drink for order number "12". This is a required identifier to get a specific item. It's part of the main instruction.

  2. Query (req.query): After specifying your drink, you add, "with oat milk and an extra shot of espresso." These are optional customizations or filters for your order.

  3. Body (req.body): You hand the barista a written note with a long, complex order for your entire team, including names, drink types, and special instructions. This data is too large and detailed to just shout out; it's a separate payload.


Decoding req.query: The "?" in the URL

The query string is the part of a URL that comes after the question mark (?). It's a set of key-value pairs used to pass optional data.

Advanced Use Cases:

  • Complex Filtering: /api/v1/articles?status=published&author=ravi
  • Pagination: /api/v1/products?limit=20&offset=40 (Fetch 20 products, skipping the first 40).
  • Search: /api/v1/search?q=express+js+tutorial
  • API Versioning: /api/users?version=2 (A less common but possible way to version APIs).

Handling Edge Cases & Best Practices:

  • Missing Parameters: What if a user visits /products without any query? req.query will be an empty object ({}). Your code should not break. Always provide sensible defaults.

    app.get('/products', (req, res) => {
      // Provide default values
      const page = parseInt(req.query.page) || 1;
      const limit = parseInt(req.query.limit) || 10;
      const sort = req.query.sort || 'name_asc';
    
      console.log(`Fetching page ${page} with ${limit} items, sorted by ${sort}`);
      // ... database logic using these safe variables
      res.send('Products are on their way!');
    });
    
  • Data Types: Remember, all values in req.query are strings. If you need a number for pagination or calculations, you must parse it using parseInt() or parseFloat(). Always check for NaN (Not a Number) if the input could be invalid.

  • Multiple Values: A client can send multiple query parameters with the same key, like /products?tags=tech&tags=new. Express is smart about this! It will parse them into an array: req.query.tags will be ['tech', 'new'].


Decoding req.params: The Dynamic URL Segments

Route parameters are named segments of the URL path used to capture required values to identify a specific resource.

Advanced Use Cases:

  • Nested Resources: /users/:userId/orders/:orderId clearly shows the relationship between a user and their specific order. This is a core pattern in REST API design.
  • Slugs for SEO: Instead of IDs, you can use user-friendly slugs: /blog/posts/:postSlug where :postSlug might be how-to-build-an-api.

Handling Edge Cases & Best Practices:

  • Validation: What if a user requests /users/abc but your IDs are numeric? The request will fail. You should validate the format of your parameters before trying to use them.

    app.get('/users/:userId', (req, res) => {
      const { userId } = req.params;
      
      // Check if userId is not a valid number
      if (isNaN(parseInt(userId))) {
        return res.status(400).send('Invalid user ID format.'); // 400 Bad Request
      }
      
      // ... proceed with fetching user
    });
    
  • Resource Not Found: The ID format is valid (/users/9999), but no user with that ID exists in your database. This is a different error! You should return a 404 Not Found.

    app.get('/users/:userId', (req, res) => {
      const user = db.users.find(u => u.id === parseInt(req.params.userId));
      
      if (!user) {
        // User with this ID does not exist
        return res.status(404).json({ error: 'User not found.' });
      }
      
      res.json(user);
    });
    

Decoding req.body: The Hidden Payload

The request body is a separate payload of data sent "inside" the HTTP request, making it perfect for sensitive or complex data in POST, PUT, and PATCH requests.

Advanced Use Cases:

  • Partial Updates (PATCH): A PATCH request might only send the fields to be changed, e.g., { "email": "new.email@example.com" }, without sending the username or password.
  • Bulk Operations: A POST to /products/bulk-delete could accept a body with an array of product IDs to delete: { "productIds": [101, 105, 210] }.

Handling Edge Cases & Best Practices:

  • Data Validation: Never trust data in req.body. Always validate it. Are required fields present? Is the email in a valid format? Is the password strong enough?

    app.post('/register', (req, res) => {
      const { email, password } = req.body;
    
      if (!email || !password) {
        return res.status(400).json({ error: 'Email and password are required.' });
      }
      if (password.length < 8) {
        return res.status(400).json({ error: 'Password must be at least 8 characters.' });
      }
      
      // ... create user
    });
    

    Pro Tip: For complex validation, use libraries like Joi or express-validator to keep your route handlers clean.

  • Malformed JSON: What if the client sends invalid JSON? The express.json() middleware will automatically catch this and produce an error. You can create a custom error-handling middleware to send a user-friendly 400 Bad Request response.

  • Body Size Limits: By default, express.json() has a size limit (e.g., 100kb) to prevent server overload. If you need to accept larger payloads (like file uploads), you can configure it:
    app.use(express.json({ limit: '5mb' }));


When to Use Which? A Quick Comparison

Feature req.query req.params req.body
Source URL Query String (after ?) URL Path Segments Request Body
Example URL /items?color=blue /items/123 /items
Common Verbs GET GET, PUT, DELETE POST, PUT, PATCH
Typical Use Filtering, sorting, searching Identifying a specific resource Sending data to create/update
Visibility ✅ Visible in URL & browser history ✅ Visible in URL & browser history ❌ Hidden from URL
Data Type Always strings Always strings Can be complex (JSON, Objects)
Setup None needed Define in route path (e.g., /:id) Middleware required (express.json())

Important Tips & Cautions

  • Always Validate: Treat all incoming data from any source (query, params, body) as untrusted. Sanitize and validate it before using it in database queries or business logic.
  • Use the Right HTTP Verb: Align your data-handling method with the HTTP verb's meaning. Don't send a body with a GET request.
  • Be Consistent: Design your API paths to be predictable. If you use /users/:id to get a user, use the same pattern for deleting (DELETE /users/:id) and updating (PUT /users/:id).
  • Send Clear Error Messages: When validation fails, send back a 400 status code with a clear message explaining what went wrong. When a resource isn't found, send a 404.

By mastering how to handle request data and its edge cases, you move from just building APIs to building robust, secure, and user-friendly ones.

Enjoy the content here?

Sign up on our platform or join our WhatsApp channel here to get more hands-on guides like this, delivered regularly.

See you in the next blog. Until then, keep practicing and happy learning!

3 Reactions

0 Bookmarks

Read next

Daksh Dixit

Daksh Dixit

Dec 29, 24

14 min read

|

Decoding the Web: A Beginner's Guide

Daksh Dixit

Daksh Dixit

Jan 5, 25

10 min read

|

Introduction to HTML, CSS, and JavaScript