Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Path parameters and query

An address often carries data: the post number in /posts/5 or the page number in /posts?page=2. The first is called a path parameter, the second a query string. Hono reads them with c.req.param() and c.req.query().

A path parameter

A parameter is marked with a colon in the route address:

// src/index.ts
app.get('/posts/:id', (c) => {
  const id = c.req.param('id')
  return c.text(`Post number ${id}`)
})

Open http://localhost:3000/posts/5 and you see "Post number 5". A parameter value is always a string, even when the address contains digits.

Finding a post by number

Combine the parameter with the post list from the previous lesson:

// src/index.ts
app.get('/posts/:id', (c) => {
  const id = Number(c.req.param('id'))
  const post = posts.find((p) => p.id === id)
 
  if (!post) {
    return c.json({ error: 'Post not found' }, 404)
  }
 
  return c.json(post)
})

/posts/1 returns the first post, and /posts/99 returns an error object with code 404.

Several parameters

// src/index.ts
app.get('/posts/:postId/comments/:commentId', (c) => {
  const { postId, commentId } = c.req.param()
  return c.text(`Comment ${commentId} on post ${postId}`)
})

Without an argument, c.req.param() returns an object with all parameters. TypeScript knows their names from the route address and suggests them in the editor.

Restricting a parameter

After the name you can put a regular expression in curly braces:

// src/index.ts
app.get('/posts/:id{[0-9]+}', (c) => c.text(`Post ${c.req.param('id')}`))

/posts/12 matches, /posts/hello does not, and Hono returns 404.

The query string

Parameters after ? are not described in the route; you read them in the handler:

// src/index.ts
app.get('/search', (c) => {
  const q = c.req.query('q') ?? ''
  const page = Number(c.req.query('page') ?? 1)
  return c.json({ q, page })
})

The address /search?q=hono&page=2 returns {"q":"hono","page":2}. When a parameter is missing, c.req.query() returns undefined, so the default value is set with ??.

MethodResult for ?tag=js&tag=ts
c.req.query('tag')'js' — the first value
c.req.queries('tag')['js', 'ts'] — all values
c.req.query()an object with all parameters

Common mistake

Comparing a parameter with a number without converting it:

// src/index.ts
const post = posts.find((p) => p.id === c.req.param('id')) // always undefined

'1' === 1 is false, so the post is never found. TypeScript underlines such a comparison, but in a JavaScript project the bug goes unnoticed. Convert the value with Number() or check it with a zod schema, as shown in the validation lesson.

Thanks for reading!

Donate to the site — we work hard for you.