Skip to content

Route Parameters and Query Strings

URLs carry data to your API in two ways: route parameters (parts of the path) and query strings (key=value pairs after ?). Understanding both is essential for building practical APIs.

A route parameter is a named dynamic segment of a URL path, prefixed with ::

app.get('/posts/:id', (req, res) => {
console.log(req.params.id) // '42' for GET /posts/42
const id = parseInt(req.params.id, 10)
// ...
})

req.params is always an object of strings — parse numbers explicitly.

app.get('/users/:userId/posts/:postId', (req, res) => {
const { userId, postId } = req.params
// GET /users/5/posts/12 → { userId: '5', postId: '12' }
})
app.get('/posts/:id?', (req, res) => {
if (req.params.id) {
// get single post
} else {
// get all posts
}
})

Query strings appear after ? in a URL and carry optional filter/sort/pagination data:

GET /posts?page=1&limit=10&sort=newest

Access them via req.query:

app.get('/posts', (req, res) => {
const page = parseInt(req.query.page as string || '1', 10)
const limit = parseInt(req.query.limit as string || '20', 10)
const sort = (req.query.sort as string) || 'newest'
console.log({ page, limit, sort })
// GET /posts?page=2&limit=5 → { page: 2, limit: 5, sort: 'newest' }
})

req.query values are strings (or arrays if the same key appears multiple times). Always parse and validate them.

Use caseApproach
Identifying a specific resourceRoute param: /posts/:id
Filtering a listQuery string: /posts?category=tech
PaginationQuery string: /posts?page=1&limit=20
SortingQuery string: /posts?sort=newest
SearchQuery string: /posts?q=javascript

Route params identify what resource you want. Query strings describe how you want it filtered or formatted.

// Get a single post by ID
app.get('/posts/:id', (req, res) => {
const post = db.prepare('SELECT * FROM posts WHERE id = ?')
.get(parseInt(req.params.id))
if (!post) return res.status(404).json({ error: 'Post not found' })
res.json(post)
})
// Get posts with optional sort
app.get('/posts', (req, res) => {
const sort = req.query.sort === 'top' ? 'upvotes DESC' : 'created_at DESC'
const posts = db.prepare(`SELECT * FROM posts ORDER BY ${sort}`).all()
res.json(posts)
})
// Get comments for a specific post
app.get('/posts/:id/comments', (req, res) => {
const comments = db.prepare('SELECT * FROM comments WHERE post_id = ?')
.all(parseInt(req.params.id))
res.json(comments)
})
  1. Update your GET /posts route to support ?sort=newest (default) and ?sort=oldest — filter the in-memory array accordingly.
  2. Add a ?limit=N query parameter that limits how many posts are returned.
  3. Test: GET /posts?sort=oldest&limit=2.
  4. What does req.query return when there are no query parameters in the URL?
  • req.params.name reads dynamic URL segments — always strings, parse numbers explicitly.
  • req.query.name reads query string values — used for filters, sorting, and pagination.
  • Route params identify a specific resource; query strings describe how to shape the response.
  • Always validate and parse query parameters — they come from user input and can’t be trusted.