Request Parameters, Query Strings, and Bodies
Three different places data arrives from in a request, each meaning something different — mixing them up is a common source of confusing bugs.
What you'll learn
- Distinguish route parameters, query strings, and the request body by purpose
- Parse a query string into a plain object
- Explain why every value from req.params and req.query arrives as a string
Prerequisites
Explanation
A single request can carry data in three genuinely different places, and each has a different intended purpose that its name reflects. Route parameters (req.params, from a path pattern like /courses/:id) identify which specific resource the request is about — a required part of the URL's structure. Query strings (req.query, from ?difficulty=beginner&sort=title after a ?) express optional filtering, sorting, or pagination — the resource collection stays the same regardless, but the query narrows or orders it. The request body (req.body, present on POST/PUT/PATCH, parsed by express.json()) carries the actual data being sent — the content of a new resource being created, or the fields being updated.
A concrete request makes this click: GET /courses/42?fields=title,progress — 42 (a route parameter) says which course; fields=title,progress (a query string) says which fields of that course to include in the response. Using the wrong one for the wrong purpose produces awkward, non-RESTful APIs — putting a resource's identity in a query string (/courses?id=42) instead of the URL path itself works technically but breaks the REST convention every other endpoint follows.
Every value in req.params and req.query arrives as a string, always — even if the URL looks like it contains a number (/courses/42), req.params.id is the string "42", not the number 42. This is a real, common bug source: comparing req.params.id === 42 (strict equality against a number) silently and always fails, since a string can never strictly equal a number in JavaScript. Explicit conversion (Number(req.params.id)) is required before any numeric comparison, exactly the pattern used in this course's earlier route-matching exercises.
Example
A real query-string parser -- the same fundamental parsing req.query does, made explicit and inspectable.
function parseQueryString(queryString) {
const result = {};
const pairs = queryString.replace(/^\?/, "").split("&");
for (const pair of pairs) {
if (!pair) continue;
const [key, value] = pair.split("=");
result[decodeURIComponent(key)] = decodeURIComponent(value || "");
}
return result;
}
console.log(parseQueryString("?difficulty=beginner&sort=title"));
// { difficulty: "beginner", sort: "title" }Try it yourself
Parse a query string with three parameters, including one with a URL-encoded space (%20 or +).
Code editor. Press Escape then Tab to leave the editor if keyboard focus becomes trapped. Press Control+Shift+M inside the editor to toggle Tab-key focus trapping.
Guided exercise
Guided exercise
A route is defined as '/courses/:id'. Given the string paramValue = '42' (exactly what req.params.id would actually be), write isMatchingCourseId(paramValue, targetId) that correctly compares it against a real number targetId, converting types correctly.
Checks: correctly matches after string-to-number conversion · correctly distinguishes match from non-match
Code editor. Press Escape then Tab to leave the editor if keyboard focus becomes trapped. Press Control+Shift+M inside the editor to toggle Tab-key focus trapping.
Stuck? Get a hint.
Independent exercise
Independent exercise
Write classifyRequestData(source) that returns 'identity' for 'route-parameter', 'filtering' for 'query-string', and 'payload' for 'request-body' -- modeling the distinct PURPOSE of each of the three data sources from this lesson.
Checks: classifies route parameters correctly · classifies query strings correctly · classifies the request body correctly
Code editor. Press Escape then Tab to leave the editor if keyboard focus becomes trapped. Press Control+Shift+M inside the editor to toggle Tab-key focus trapping.
Stuck? Get a hint.
Common mistakes
- Comparing req.params.id directly against a number with strict equality, forgetting that route parameters always arrive as strings.
- Putting a resource's identity in a query string (`/courses?id=42`) instead of the URL path (`/courses/42`), breaking REST convention.
- Using the request body for data that should be a query parameter (like pagination on a GET request, which conventionally has no body at all).
Knowledge check
Takeaway
Route parameters identify which resource, query strings express optional filtering, and the request body carries the actual data — and every params/query value arrives as a string, requiring explicit conversion before numeric comparisons.
Summary
This lesson distinguished the three sources of request data by purpose and built a real query-string parser, then covered the common string-vs-number bug that comes from forgetting req.params values are always strings.
References
Your notes
Notes save automatically.
Finished this lesson?
Mark it complete to track your progress and schedule a future review.
AI tutor
The optional AI tutor isn't enabled in this deployment. All lessons, exercises, quizzes, and search work fully without it.