
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:
-
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. -
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. -
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 usingparseInt()
orparseFloat()
. Always check forNaN
(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 behow-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 a404 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
): APATCH
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
orexpress-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-friendly400 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 a404
.
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