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 method | What it returns |
|---|---|
c.req.method | the HTTP method |
c.req.path | the path without the domain and the query string |
c.req.url | the 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.raw | the original Request object |
Response methods
Each method creates a Response object, which the handler returns:
| Method | Response |
|---|---|
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.