intermediate18 min

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,progress42 (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.

Loading editor…

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.

Loading editor…

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.

Loading editor…

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

Knowledge check

1. What is the conventional purpose of a route parameter versus a query string?
2. Why does `req.params.id === 42` (strict equality against a number) always fail for a route like `/courses/:id`?
3. What data source is appropriate for the content of a new resource being created via POST?

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.