Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

The Context object

Every handler receives one argument — the context, usually named c. A new context is created for each request and holds everything you need: the request itself in c.req and the methods that build the response.

Request data

c.req wraps the standard Request object and adds handy methods:

// src/index.ts
app.get('/info', (c) => {
  return c.json({
    method: c.req.method,
    path: c.req.path,
    url: c.req.url,
    agent: c.req.header('User-Agent'),
  })
})

Open http://localhost:3000/info and the response contains the method GET, the path /info, the full address and a string naming your browser.

Property or methodWhat it returns
c.req.methodthe HTTP method
c.req.paththe path without the domain and the query string
c.req.urlthe full address
c.req.header('Name')the header value or undefined
c.req.param(), c.req.query()address parameters, covered in the previous lesson
c.req.rawthe original Request object

Response methods

Each method creates a Response object, which the handler returns:

MethodResponse
c.text('Hello')plain text
c.json(data)JSON
c.html('<h1>Blog</h1>')HTML markup
c.redirect('/posts')a redirect to another address
c.body(null, 204)a response with no preset format, for example an empty one
c.notFound()a 404 response

Status code

Pass the code as the second argument or set it beforehand with c.status():

// src/index.ts
app.post('/posts', (c) => {
  c.status(201)
  return c.json({ message: 'Post created' })
})

The response comes with code 201 Created. Writing c.json({ ... }, 201) does the same.

Headers

c.header() adds a header to the upcoming response:

// src/index.ts
app.get('/posts', (c) => {
  c.header('X-Total-Count', String(posts.length))
  return c.json(posts)
})

curl -i http://localhost:3000/posts shows x-total-count: 2 among the headers.

HTML and redirects

// src/index.ts
app.get('/', (c) => c.html('<h1>Blog</h1><p><a href="/posts">Posts</a></p>'))
 
app.get('/blog', (c) => c.redirect('/'))

The home page shows a heading and a link, and /blog sends the browser to /. By default c.redirect() answers with code 302; a permanent redirect is c.redirect('/', 301).

Common mistake

Putting user data into c.html() through a plain template string:

// src/index.ts
app.get('/hello', (c) => c.html(`<h1>Hello, ${c.req.query('name')}</h1>`))

The string goes into the page as is. If someone passes a script tag in name, the browser runs foreign code. For HTML with data use JSX from the lesson on pages: it escapes values itself.

Thanks for reading!

Donate to the site — we work hard for you.