Context
Request와 Response를 처리하기 위해 Context 객체를 사용할 수 있다.
req
req는 HonoRequest의 인스턴스이다. 자세한 내용은 HonoRequest를 참조한다.
import { Hono } from 'hono'
const app = new Hono()
// ---cut---
app.get('/hello', (c) => {
const userAgent = c.req.header('User-Agent')
// ...
// ---cut-start---
return c.text(`Hello, ${userAgent}`)
// ---cut-end---
})body()
HTTP 응답을 반환한다.
c.header()로 헤더를 설정하고 c.status로 HTTP 상태 코드를 지정할 수 있다. 이는 c.text(), c.json() 등에서도 설정 가능하다.
INFO
참고: 텍스트나 HTML을 반환할 때는 c.text()나 c.html()을 사용하는 것이 좋다.
import { Hono } from 'hono'
const app = new Hono()
// ---cut---
app.get('/welcome', (c) => {
// 헤더 설정
c.header('X-Message', 'Hello!')
c.header('Content-Type', 'text/plain')
// HTTP 상태 코드 설정
c.status(201)
// 응답 본문 반환
return c.body('Thank you for coming')
})다음과 같이 작성할 수도 있다.
import { Hono } from 'hono'
const app = new Hono()
// ---cut---
app.get('/welcome', (c) => {
return c.body('Thank you for coming', 201, {
'X-Message': 'Hello!',
'Content-Type': 'text/plain',
})
})위 코드는 아래와 동일한 응답을 생성한다.
new Response('Thank you for coming', {
status: 201,
headers: {
'X-Message': 'Hello!',
'Content-Type': 'text/plain',
},
})text()
Content-Type:text/plain으로 텍스트를 렌더링한다.
import { Hono } from 'hono'
const app = new Hono()
// ---cut---
app.get('/say', (c) => {
return c.text('Hello!')
})json()
JSON을 Content-Type:application/json으로 렌더링한다.
import { Hono } from 'hono'
const app = new Hono()
// ---cut---
app.get('/api', (c) => {
return c.json({ message: 'Hello!' })
})html()
Content-Type:text/html로 HTML을 렌더링한다.
import { Hono } from 'hono'
const app = new Hono()
// ---cut---
app.get('/', (c) => {
return c.html('<h1>Hello! Hono!</h1>')
})notFound()
Not Found 응답을 반환한다.
import { Hono } from 'hono'
const app = new Hono()
// ---cut---
app.get('/notfound', (c) => {
return c.notFound()
})redirect()
redirect()는 기본 상태 코드로 302를 사용한다.
import { Hono } from 'hono'
const app = new Hono()
// ---cut---
app.get('/redirect', (c) => {
return c.redirect('/')
})
app.get('/redirect-permanently', (c) => {
return c.redirect('/', 301)
})res
import { Hono } from 'hono'
const app = new Hono()
// ---cut---
// Response 객체
app.use('/', async (c, next) => {
await next()
c.res.headers.append('X-Debug', 'Debug message')
})set() / get()
현재 요청 동안 임의의 키-값 쌍을 설정하고 가져올 수 있다. 이를 통해 미들웨어 간 또는 미들웨어에서 라우트 핸들러로 특정 값을 전달할 수 있다.
import { Hono } from 'hono'
const app = new Hono<{ Variables: { message: string } }>()
// ---cut---
app.use(async (c, next) => {
c.set('message', 'Hono is cool!!')
await next()
})
app.get('/', (c) => {
const message = c.get('message')
return c.text(`The message is "${message}"`)
})타입 안전성을 보장하려면 Hono 생성자에 Variables를 제네릭으로 전달한다.
import { Hono } from 'hono'
// ---cut---
type Variables = {
message: string
}
const app = new Hono<{ Variables: Variables }>()c.set / c.get의 값은 동일한 요청 내에서만 유지된다. 다른 요청 간에 공유하거나 유지할 수 없다.
변수
c.var를 사용해 변수의 값에 접근할 수 있다.
import type { Context } from 'hono'
declare const c: Context
// ---cut---
const result = c.var.client.oneMethod()커스텀 메서드를 제공하는 미들웨어를 만들려면 다음과 같이 작성한다.
import { Hono } from 'hono'
import { createMiddleware } from 'hono/factory'
// ---cut---
type Env = {
Variables: {
echo: (str: string) => string
}
}
const app = new Hono()
const echoMiddleware = createMiddleware<Env>(async (c, next) => {
c.set('echo', (str) => str)
await next()
})
app.get('/echo', echoMiddleware, (c) => {
return c.text(c.var.echo('Hello!'))
})여러 핸들러에서 미들웨어를 사용하려면 app.use()를 활용한다. 이때 타입 안전성을 보장하려면 Hono 생성자에 Env를 제네릭으로 전달해야 한다.
import { Hono } from 'hono'
import type { MiddlewareHandler } from 'hono/types'
declare const echoMiddleware: MiddlewareHandler
type Env = {
Variables: {
echo: (str: string) => string
}
}
// ---cut---
const app = new Hono<Env>()
app.use(echoMiddleware)
app.get('/echo', (c) => {
return c.text(c.var.echo('Hello!'))
})render() / setRenderer()
커스텀 미들웨어 내에서 c.setRenderer()를 사용해 레이아웃을 설정할 수 있다.
/** @jsx jsx */
/** @jsxImportSource hono/jsx */
import { Hono } from 'hono'
const app = new Hono()
// ---cut---
app.use(async (c, next) => {
c.setRenderer((content) => {
return c.html(
<html>
<body>
<p>{content}</p>
</body>
</html>
)
})
await next()
})그런 다음, 이 레이아웃 내에서 응답을 생성하기 위해 c.render()를 활용할 수 있다.
import { Hono } from 'hono'
const app = new Hono()
// ---cut---
app.get('/', (c) => {
return c.render('Hello!')
})이 코드의 출력 결과는 다음과 같다:
<html>
<body>
<p>Hello!</p>
</body>
</html>또한, 이 기능은 인자를 커스텀할 수 있는 유연성을 제공한다. 타입 안전성을 보장하기 위해 다음과 같이 타입을 정의할 수 있다:
declare module 'hono' {
interface ContextRenderer {
(
content: string | Promise<string>,
head: { title: string }
): Response | Promise<Response>
}
}이를 활용한 예제는 다음과 같다:
app.use('/pages/*', async (c, next) => {
c.setRenderer((content, head) => {
return c.html(
<html>
<head>
<title>{head.title}</title>
</head>
<body>
<header>{head.title}</header>
<p>{content}</p>
</body>
</html>
)
})
await next()
})
app.get('/pages/my-favorite', (c) => {
return c.render(<p>Ramen and Sushi</p>, {
title: 'My favorite',
})
})
app.get('/pages/my-hobbies', (c) => {
return c.render(<p>Watching baseball</p>, {
title: 'My hobbies',
})
})실행 컨텍스트
import { Hono } from 'hono'
const app = new Hono<{
Bindings: {
KV: any
}
}>()
declare const key: string
declare const data: string
// ---cut---
// ExecutionContext 객체
app.get('/foo', async (c) => {
c.executionCtx.waitUntil(c.env.KV.put(key, data))
// ...
})이벤트
import { Hono } from 'hono'
declare const key: string
declare const data: string
type KVNamespace = any
// ---cut---
// 타입 추론을 위한 타입 정의
type Bindings = {
MY_KV: KVNamespace
}
const app = new Hono<{ Bindings: Bindings }>()
// FetchEvent 객체 (Service Worker 구문 사용 시에만 설정됨)
app.get('/foo', async (c) => {
c.event.waitUntil(c.env.MY_KV.put(key, data))
// ...
})환경 변수
Cloudflare Workers에서 환경 변수, 시크릿, KV 네임스페이스, D1 데이터베이스, R2 버킷 등 워커에 바인딩된 요소를 바인딩(bindings)이라고 한다. 타입에 상관없이 바인딩은 항상 전역 변수로 사용할 수 있으며, c.env.BINDING_KEY를 통해 접근할 수 있다.
import { Hono } from 'hono'
type KVNamespace = any
// ---cut---
// 타입 추론을 위한 타입 정의
type Bindings = {
MY_KV: KVNamespace
}
const app = new Hono<{ Bindings: Bindings }>()
// Cloudflare Workers의 환경 객체
app.get('/', async (c) => {
c.env.MY_KV.get('my-key')
// ...
})오류 처리
핸들러에서 오류가 발생하면, 해당 오류 객체는 c.error에 저장된다. 미들웨어에서 이 오류 객체에 접근할 수 있다.
import { Hono } from 'hono'
const app = new Hono()
// ---cut---
app.use(async (c, next) => {
await next()
if (c.error) {
// 오류 처리 로직...
}
})ContextVariableMap
특정 미들웨어를 사용할 때 변수에 타입 정의를 추가하려면 ContextVariableMap을 확장하면 된다. 예를 들어:
declare module 'hono' {
interface ContextVariableMap {
result: string
}
}이를 미들웨어에서 활용할 수 있다:
import { createMiddleware } from 'hono/factory'
// ---cut---
const mw = createMiddleware(async (c, next) => {
c.set('result', 'some values') // result는 string 타입
await next()
})핸들러에서는 변수가 적절한 타입으로 추론된다:
import { Hono } from 'hono'
const app = new Hono<{ Variables: { result: string } }>()
// ---cut---
app.get('/', (c) => {
const val = c.get('result') // val은 string 타입
// ...
return c.json({ result: val })
})