빠르게 진화하는 웹 개발 세계에서 올바른 프레임워크를 찾는 것은 어려울 수 있습니다. 빠르고 가벼우며 다양한 환경에서 작업할 수 있을 만큼 유연한 것을 원할 것입니다. 여기에 Hono가 있습니다. Hono는 인상적인 속도, 최소한의 설치 공간, 개발자 친화적인 디자인으로 개발자들 사이에서 빠르게 인기를 얻고 있는 웹 프레임워크입니다.
Hono(일본어로 "불꽃" 🔥을 의미)는 이름에 걸맞게 매우 빠르며 우아한 단순함으로 개발 경험을 밝혀줍니다. API, 마이크로서비스 또는 풀스택 애플리케이션을 구축하든 관계없이 Hono는 더 무거운 프레임워크에 대한 매력적인 대안을 제공합니다.
이 가이드는 Hono.js를 시작하는 데 필요한 모든 것, 즉 설치부터 첫 번째 애플리케이션 구축 및 핵심 개념 이해까지 안내합니다.
개발 팀이 최대 생산성으로 함께 작업할 수 있는 통합된 올인원 플랫폼을 원하십니까?
Apidog는 귀하의 모든 요구 사항을 충족하며 훨씬 저렴한 가격으로 Postman을 대체합니다!
Hono란 무엇인가요?

Hono는 웹 표준을 기반으로 구축된 작고 단순하며 매우 빠른 웹 프레임워크입니다. Cloudflare Workers, Fastly Compute, Deno, Bun, Vercel, Netlify, AWS Lambda, Lambda@Edge, Node.js 등 거의 모든 JavaScript 런타임에서 작동합니다.
핵심적으로 Hono는 웹 표준 API(Request, Response, Fetch 등)를 수용하여 플랫폼 간 뛰어난 이식성을 제공합니다. 이는 코드를 한 번 작성하면 큰 수정 없이 거의 모든 곳에 배포할 수 있음을 의미합니다.
import { Hono } from 'hono'
const app = new Hono()
app.get('/', (c) => c.text('Hono!'))
export default app
이 간단한 예제는 Express에서 영감을 받았지만 오늘날의 JavaScript 생태계에 맞게 현대화된 Hono의 깔끔한 구문을 보여줍니다.
시작해 봅시다!
1. Bun을 사용하여 Hono.js 설치 및 프로젝트 설정
Bun은 속도와 패키지 관리자, 번들러, 테스트 러너를 포함한 올인원 툴킷으로 알려진 최신 JavaScript 런타임입니다. Bun으로 Hono를 설정하는 것은 간단합니다.
전제 조건
Bun이 설치되어 있는지 확인하세요. 설치되어 있지 않다면 공식 Bun 웹사이트의 지침에 따라 설치할 수 있습니다.
Bun으로 새 Hono 프로젝트 생성하기
Bun으로 새 Hono 프로젝트를 시작하는 가장 빠른 방법은 create-hono
스캐폴딩 도구를 사용하는 것입니다.
bun create hono@latest my-hono-app
이 명령은 템플릿을 선택하라는 메시지를 표시합니다. 이 가이드에서는 bun
템플릿을 선택합니다.
? Which template do you want to use? › - Use arrow keys. Return to submit.
❯ bun
cloudflare-workers
cloudflare-pages
deno
fastly
netlify
nodejs
vercel
템플릿을 선택한 후 새 프로젝트 디렉토리로 이동하여 종속성을 설치합니다.
cd my-hono-app
bun install
기존 Bun 프로젝트에 Hono 추가하기
기존 Bun 프로젝트가 있다면 Hono를 종속성으로 추가할 수 있습니다.
bun add hono
2. Hono.js로 기본 애플리케이션 구축하기: "Hello Hono!"
간단한 "Hello World"(아니면 "Hello Hono!") 애플리케이션을 만들어 봅시다.
프로젝트 내부에 src
디렉토리가 있어야 합니다. src/index.ts
파일을 생성하거나 엽니다 (일반 JavaScript를 선호하는 경우 index.js
를 사용해도 되지만, Hono의 모든 이점을 위해서는 TypeScript가 권장됩니다).
// src/index.ts
import { Hono } from 'hono'
const app = new Hono()
app.get('/', (c) => {
return c.text('Hello Hono!')
})
export default app
이것을 자세히 살펴보겠습니다.
hono
패키지에서Hono
클래스를 가져옵니다.- 일반적으로
app
이라는 이름으로Hono
의 새 인스턴스를 생성합니다. - 루트 경로(
/
)에 대한GET
요청을 위한 경로를 정의합니다. - 경로 핸들러는
Context
객체(관례적으로c
)를 인수로 받는 함수입니다. c.text('Hello Hono!')
는 일반 텍스트 "Hello Hono!"를 포함하는Response
객체를 생성합니다.- 마지막으로
app
인스턴스를 내보냅니다. Bun의 경우 이 기본 내보내기는 개발 서버가 이를 인식하는 데 충분합니다.
애플리케이션 실행하기
개발 모드에서 애플리케이션을 실행하려면 package.json
에 정의된 dev
스크립트를 사용합니다 (create-hono
가 자동으로 설정해 줍니다).
bun run dev
일반적으로 http://localhost:3000
에서 서버가 시작됩니다. 웹 브라우저에서 이 URL을 열면 "Hello Hono!"가 표시될 것입니다.
포트 변경하기
다른 포트에서 애플리케이션을 실행해야 하는 경우 src/index.ts
에서 내보내기를 수정할 수 있습니다.
// src/index.ts
import { Hono } from 'hono'
const app = new Hono()
app.get('/', (c) => {
return c.text('Hello Hono on port 8080!')
})
export default {
port: 8080, // 원하는 포트 지정
fetch: app.fetch,
}
이제 bun run dev
를 실행하면 애플리케이션이 http://localhost:8080
에서 제공됩니다.
3. Hono.js로 기본 API 구축하기
Hono는 API 구축에 뛰어납니다. 라우팅, 요청 처리 및 응답 생성 방법을 살펴보겠습니다.
라우팅
Hono의 라우팅은 직관적입니다. app
인스턴스에는 HTTP 동사(.get()
, .post()
, .put()
, .delete()
등)에 해당하는 메서드가 있습니다.
기본 GET 경로
이미 기본 GET 경로를 살펴보았습니다.
app.get('/hello', (c) => {
return c.text('Hello, world!')
})
경로 매개변수
:paramName
구문을 사용하여 경로 매개변수가 있는 경로를 정의할 수 있습니다. 이러한 매개변수는 c.req.param('paramName')
을 통해 액세스할 수 있습니다.
// 예제: /users/123
app.get('/users/:id', (c) => {
const userId = c.req.param('id')
return c.text(`User ID: ${userId}`)
})
쿼리 매개변수
URL의 쿼리 매개변수(예: /search?q=hono
)는 c.req.query('queryName')
을 사용하여 액세스할 수 있습니다.
// 예제: /search?category=frameworks&limit=10
app.get('/search', (c) => {
const category = c.req.query('category')
const limit = c.req.query('limit')
return c.text(`Searching in category: ${category}, Limit: ${limit}`)
})
c.req.query()
를 사용하여 모든 쿼리 매개변수를 객체로 가져올 수도 있습니다.
다양한 HTTP 메서드 처리하기
Hono는 동일한 경로에 대해 다양한 HTTP 메서드를 쉽게 처리할 수 있도록 합니다.
// src/index.ts
import { Hono } from 'hono'
const app = new Hono()
// GET 게시물 목록
app.get('/posts', (c) => {
// 실제 앱에서는 데이터베이스에서 가져올 것입니다
const posts = [
{ id: '1', title: 'Hono 시작하기' },
{ id: '2', title: '고급 Hono 기법' },
];
return c.json(posts); // JSON 응답 반환
})
// ID로 단일 게시물 가져오기
app.get('/posts/:id', (c) => {
const id = c.req.param('id')
// 데이터베이스에서 ID로 게시물 가져오기
const post = { id: id, title: `게시물 ${id}`, content: '이것은 내용입니다...' };
if (!post) {
return c.notFound() // 404를 위한 내장 헬퍼
}
return c.json(post)
})
// 새 게시물 생성
app.post('/posts', async (c) => {
const body = await c.req.json() // JSON 본문 파싱
// 실제 앱에서는 데이터베이스에 저장할 것입니다
console.log('게시물 생성:', body)
return c.json({ message: '게시물이 성공적으로 생성되었습니다!', data: body }, 201) // 201 Created로 응답
})
// 기존 게시물 업데이트
app.put('/posts/:id', async (c) => {
const id = c.req.param('id')
const body = await c.req.json()
// 데이터베이스에서 게시물 업데이트
console.log(`게시물 ${id} 업데이트:`, body)
return c.json({ message: `게시물 ${id}이 성공적으로 업데이트되었습니다!`, data: body })
})
// 게시물 삭제
app.delete('/posts/:id', (c) => {
const id = c.req.param('id')
// 데이터베이스에서 게시물 삭제
console.log(`게시물 ${id} 삭제`)
return c.json({ message: `게시물 ${id}이 성공적으로 삭제되었습니다!` })
})
export default {
port: 3000,
fetch: app.fetch
}
요청 객체 (c.req
)
Context
객체(c
)는 c.req
를 통해 요청 세부 정보에 대한 액세스를 제공합니다. 주요 속성 및 메서드는 다음과 같습니다.
c.req.url
: 전체 URL 문자열입니다.c.req.method
: HTTP 메서드(예: 'GET', 'POST')입니다.c.req.headers
: Headers 객체입니다.c.req.header('Content-Type')
과 같이 헤더에 액세스합니다.c.req.param('name')
: 경로 매개변수를 가져옵니다.c.req.query('name')
: 쿼리 매개변수를 가져옵니다.c.req.queries('name')
: 반복되는 쿼리 매개변수의 모든 값을 배열로 가져옵니다.c.req.json()
: 요청 본문을 JSON으로 파싱합니다. (Promise 반환)c.req.text()
: 요청 본문을 일반 텍스트로 읽습니다. (Promise 반환)c.req.arrayBuffer()
: 요청 본문을 ArrayBuffer로 읽습니다. (Promise 반환)c.req.formData()
: 요청 본문을 FormData로 파싱합니다. (Promise 반환)c.req.valid('type')
: 유효성 검사된 데이터에 액세스합니다 (나중에 다룰 유효성 검사기와 함께 사용).
응답 객체 (c
) 및 헬퍼
Context
객체(c
)는 Response
객체 생성을 위한 편리한 헬퍼도 제공합니다.
c.text(text, status?, headers?)
: 일반 텍스트 응답을 반환합니다.c.json(object, status?, headers?)
: JSON 응답을 반환합니다. Content-Type은 자동으로application/json
으로 설정됩니다.c.html(html, status?, headers?)
: HTML 응답을 반환합니다.c.redirect(location, status?)
: 리다이렉트 응답을 반환합니다 (기본 상태 302).c.notFound()
: 404 Not Found 응답을 반환합니다.c.newResponse(body, status?, headers?)
: 새Response
객체를 생성합니다.body
는null
,ReadableStream
,ArrayBuffer
,FormData
,URLSearchParams
또는string
일 수 있습니다.c.header(name, value)
: 응답 헤더를 설정합니다.
예제: 사용자 정의 헤더 설정
app.get('/custom-header', (c) => {
c.header('X-Powered-By', 'HonoJS-Flame')
c.header('Cache-Control', 'no-cache')
return c.text('응답 헤더를 확인하세요!')
})
4. Hono.js에서 미들웨어 작업하기
미들웨어 함수는 Hono(및 많은 웹 프레임워크)의 핵심 요소입니다. 이 함수는 요청이 주 경로 핸들러에 도달하기 전에 요청을 처리하거나, 핸들러가 실행된 후 응답을 처리할 수 있습니다. 미들웨어는 로깅, 인증, 데이터 유효성 검사, 압축, CORS 등과 같은 작업에 유용합니다.
미들웨어 함수의 기본 시그니처는 async (c, next) => { ... }
입니다.
c
: Context 객체입니다.next
: 체인의 다음 미들웨어 또는 최종 경로 핸들러로 제어를 전달하기 위해 호출하는 함수입니다. 후속 미들웨어 또는 핸들러를 실행하려면await next()
를 호출해야 합니다.
내장 미들웨어 사용하기
Hono는 풍부한 내장 미들웨어 세트와 함께 제공됩니다. hono/middleware-name
에서 가져올 수 있습니다 (예: hono/logger
, hono/cors
).
모든 경로에 미들웨어를 적용하려면 app.use(middlewareFunction)
를 사용합니다.
특정 경로에 미들웨어를 적용하려면 첫 번째 인수로 경로 패턴을 제공합니다: app.use('/admin/*', authMiddleware)
.
예제: 로거 및 ETag 미들웨어
// src/index.ts
import { Hono } from 'hono'
import { logger } from 'hono/logger'
import { etag } from 'hono/etag'
import { prettyJSON } from 'hono/pretty-json' // JSON 응답 서식 지정
const app = new Hono()
// 모든 경로에 미들웨어 적용
app.use(logger()) // 요청 및 응답 정보를 콘솔에 기록
app.use(etag()) // 캐싱을 위한 ETag 헤더 추가
app.use(prettyJSON()) // JSON 응답 서식을 들여쓰기로 지정
app.get('/', (c) => {
return c.text('로거와 ETag가 있는 Hello!')
})
app.get('/data', (c) => {
return c.json({ message: '이것은 일부 데이터입니다.', timestamp: Date.now() })
})
export default app
이를 실행하고 /
또는 /data
에 액세스하면 콘솔에 로그가 표시되고 응답에 ETag
헤더가 포함됩니다. /data
의 JSON 응답은 보기 좋게 서식이 지정됩니다.
유용한 다른 내장 미들웨어:
cors
: 교차 출처 리소스 공유를 처리합니다.basicAuth
: 기본 인증을 구현합니다.jwt
: JWT(JSON 웹 토큰) 인증입니다.compress
: 응답 본문을 압축합니다.cache
: Cache API를 사용하여 캐싱을 구현합니다.secureHeaders
: 다양한 보안 관련 HTTP 헤더를 추가합니다.bodyLimit
: 요청 본문의 크기를 제한합니다.
Hono 문서의 "Middleware" 섹션에서 전체 목록과 문서를 찾을 수 있습니다.
사용자 정의 미들웨어 생성하기
자신만의 미들웨어를 쉽게 작성할 수 있습니다.
예제 1: 간단한 요청 타이머
// src/index.ts
import { Hono } from 'hono'
import { logger } from 'hono/logger'
const app = new Hono()
app.use(logger())
// 요청 처리 시간을 측정하는 사용자 정의 미들웨어
app.use(async (c, next) => {
const start = Date.now()
console.log(`요청 수신 시간: ${new Date(start).toISOString()}`)
await next() // 다음 미들웨어 또는 경로 핸들러 호출
const ms = Date.now() - start
c.header('X-Response-Time', `${ms}ms`) // 응답에 사용자 정의 헤더 추가
console.log(`요청 처리 시간: ${ms}ms`)
})
app.get('/', (c) => {
return c.text('사용자 정의 타이밍 미들웨어가 있는 Hono에서 안녕하세요!')
})
app.get('/slow', async (c) => {
// 느린 작업 시뮬레이션
await new Promise(resolve => setTimeout(resolve, 1500))
return c.text('이것은 느린 응답이었습니다.')
})
export default app
/
및 /slow
에 액세스하여 타이밍 로그와 X-Response-Time
헤더를 확인하세요.
예제 2: 간단한 API 키 인증 미들웨어
이것은 데모를 위한 매우 기본적인 예제입니다. 실제 애플리케이션에서는 JWT 또는 OAuth와 같은 더 강력한 인증 방법을 사용하고 API 키를 안전하게 저장하세요.
// src/index.ts
import { Hono } from 'hono'
import { logger } from 'hono/logger'
import { HTTPException } from 'hono/http-exception' // 표준 HTTP 오류 발생
const app = new Hono()
app.use(logger())
const API_KEY = "supersecretapikey"; // 실제 앱에서는 안전하게 저장 (예: 환경 변수)
// 사용자 정의 API 키 인증 미들웨어
const apiKeyAuth = async (c, next) => {
const apiKeyHeader = c.req.header('X-API-KEY')
if (apiKeyHeader && apiKeyHeader === API_KEY) {
await next()
} else {
// HTTPException을 사용하여 표준화된 오류 응답 반환
throw new HTTPException(401, { message: '권한 없음: 잘못된 API 키' })
}
}
// 특정 경로 그룹에 이 미들웨어 적용
app.use('/api/v1/*', apiKeyAuth)
app.get('/api/v1/me', (c) => {
return c.json({ user: '인증된 사용자', email: 'user@example.com' })
})
app.get('/public/info', (c) => {
return c.text('이것은 공개 정보이며 API 키가 필요하지 않습니다.')
})
// HTTPException에 대한 오류 핸들러
app.onError((err, c) => {
if (err instanceof HTTPException) {
return err.getResponse()
}
// 다른 오류의 경우
console.error('처리되지 않은 오류:', err)
return c.text('내부 서버 오류', 500)
})
export default app
테스트하려면:
curl http://localhost:3000/api/v1/me
(401 Unauthorized 반환 예상)curl -H "X-API-KEY: supersecretapikey" http://localhost:3000/api/v1/me
(사용자 데이터 반환 예상)curl http://localhost:3000/public/info
(공개 정보 반환 예상)
createMiddleware로 사용자 정의 미들웨어 재사용하기
더 복잡하거나 재사용 가능한 미들웨어의 경우 hono/factory
의 createMiddleware
를 사용하여 별도로 정의할 수 있습니다. 이는 TypeScript 타입 추론에도 도움이 됩니다.
// src/middlewares/timing.ts
import { createMiddleware } from 'hono/factory'
export const timingMiddleware = createMiddleware(async (c, next) => {
const start = Date.now()
await next()
const ms = Date.now() - start
c.res.headers.set('X-Response-Time', `${ms}ms`) // 참고: c.res.headers.set
console.log(` -> 처리 시간: ${ms}ms`)
})
// src/middlewares/auth.ts
import { createMiddleware } from 'hono/factory'
import { HTTPException } from 'hono/http-exception'
const VALID_API_KEY = "anothersecretkey";
// 미들웨어에 환경 변수가 필요한 경우 타입
type Env = {
Variables: {
user?: { id: string } // 예제: 인증 후 사용자 데이터 설정
}
// Bindings: { MY_KV_NAMESPACE: KVNamespace } // Cloudflare Workers 예제
}
export const secureApiKeyAuth = createMiddleware<Env>(async (c, next) => {
const apiKey = c.req.header('Authorization')?.replace('Bearer ', '')
if (apiKey === VALID_API_KEY) {
// 선택 사항: 다운스트림 핸들러를 위해 컨텍스트에 변수 설정
c.set('user', { id: 'user123' })
await next()
} else {
throw new HTTPException(401, { message: '액세스 거부: 보안 API 키 필요.'})
}
})
// src/index.ts
import { Hono } from 'hono'
import { logger } from 'hono/logger'
import { timingMiddleware } from './middlewares/timing' // middlewares 폴더에 있다고 가정
import { secureApiKeyAuth } from './middlewares/auth'
const app = new Hono()
app.use(logger())
app.use(timingMiddleware) // 모든 경로에 적용
app.get('/', (c) => {
return c.text('팩토리드 미들웨어가 있는 Hono에서 안녕하세요!')
})
app.use('/secure/data/*', secureApiKeyAuth) // /secure/data/*에만 적용
app.get('/secure/data/profile', (c) => {
// const user = c.get('user') // 미들웨어에 의해 설정된 변수 액세스
return c.json({ profileData: '민감한 프로필 정보', /*user: user*/ })
})
app.get('/public/data', (c) => {
return c.text('이것은 공개 데이터이며 키가 필요하지 않습니다.')
})
// 일반 오류 핸들러
app.onError((err, c) => {
if (err instanceof HTTPException) {
return err.getResponse();
}
console.error('오류:', err.message);
return c.json({ error: '내부 서버 오류', message: err.message }, 500);
});
export default app
이 구조는 미들웨어를 더 모듈화하고 독립적으로 테스트하기 쉽게 만듭니다.
5. Hono.js 애플리케이션 테스트하기
Hono는 쉽게 테스트할 수 있도록 설계되었습니다. Bun은 Hono와 잘 작동하는 자체 테스트 러너인 bun:test
와 함께 제공됩니다. Vitest와 같은 다른 테스트 러너를 사용할 수도 있습니다.
bun:test 사용하기 (기본)
bun.md
문서는 bun:test
를 사용한 테스트의 기본 예제를 제공합니다.
예를 들어 src/index.test.ts
와 같은 테스트 파일을 생성합니다.
// src/index.test.ts
import { describe, expect, it } from 'bun:test'
import app from '.' // src/index.ts에서 앱 가져오기
describe('Hono Application Tests', () => {
it('GET /에 대해 200 OK를 반환해야 함', async () => {
const req = new Request('http://localhost/') // 여기서는 기본 URL이 크게 중요하지 않음
const res = await app.fetch(req)
expect(res.status).toBe(200)
expect(await res.text()).toBe('Hello Hono!') // 또는 루트 경로가 반환하는 내용
})
it('GET /posts에 대해 JSON을 반환해야 함', async () => {
const req = new Request('http://localhost/posts')
const res = await app.fetch(req)
expect(res.status).toBe(200)
const json = await res.json()
expect(json).toBeArray() // /posts가 배열을 반환한다고 가정
// 필요한 경우 JSON 내용에 대한 더 구체적인 검증 추가
})
it('POST /posts에 대해 게시물을 생성해야 함', async () => {
const postData = { title: '테스트 게시물', content: '이것은 테스트입니다.' };
const req = new Request('http://localhost/posts', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(postData),
});
const res = await app.fetch(req);
expect(res.status).toBe(201); // 201 Created 예상
const jsonResponse = await res.json();
expect(jsonResponse.message).toBe('게시물이 성공적으로 생성되었습니다!');
expect(jsonResponse.data.title).toBe(postData.title);
});
})
테스트를 실행하려면:
bun test
또는 특정 파일을 실행하려면:
bun test src/index.test.ts
app.request() 헬퍼 사용하기
Hono는 전체 Request
객체를 매번 구성하는 대신 경로와 옵션을 직접 전달하여 테스트를 단순화하는 편리한 app.request()
메서드를 제공합니다. 이는 docs/guides/testing.md
에 나와 있습니다.
// src/index.test.ts
import { describe, expect, it } from 'bun:test' // 또는 'vitest'에서 가져오기
import app from '.' // Hono 앱 인스턴스
describe('app.request()가 있는 Hono 앱', () => {
it('GET /은 "Hello Hono!"를 반환해야 함', async () => {
const res = await app.request('/')
expect(res.status).toBe(200)
expect(await res.text()).toBe('Hello Hono!') // 실제 루트 응답에 맞게 조정
})
it('GET /posts/:id는 특정 게시물을 반환해야 함', async () => {
// 앱에 app.get('/posts/:id', ...)와 같은 경로가 있다고 가정
// 이 테스트에서는 { id: '123', title: '테스트 게시물 123' }을 반환할 수 있음
const res = await app.request('/posts/123')
expect(res.status).toBe(200)
const data = await res.json()
expect(data.id).toBe('123')
// expect(data.title).toBe('Post 123') // 또는 앱 로직에 따라
})
it('POST /posts는 새 게시물을 생성해야 함', async () => {
const newPost = { title: '내 새 게시물', content: '멋진 내용입니다.' }
// JSON 본문이 있는 POST, PUT 등은 client.path.$post({ json: payload })와 같음
const res = await app.request('/posts', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(newPost),
})
expect(res.status).toBe(201) // POST /posts가 201을 반환한다고 가정
const responseData = await res.json()
expect(responseData.message).toBe('게시물이 성공적으로 생성되었습니다!')
expect(responseData.data.title).toBe(newPost.title)
})
it('API 키 없는 GET /api/v1/me는 401이어야 함', async () => {
// 이전 예제의 API 키 미들웨어가 이 경로에서 활성화되어 있다고 가정
const res = await app.request('/api/v1/me')
expect(res.status).toBe(401)
})
it('올바른 API 키가 있는 GET /api/v1/me는 200이어야 함', async () => {
const res = await app.request('/api/v1/me', {
headers: {
'X-API-KEY': 'supersecretapikey' // 미들웨어의 키 사용
}
})
expect(res.status).toBe(200)
const data = await res.json();
expect(data.user).toBe('인증된 사용자')
})
})
타입 안전 테스트를 위한 testClient() 헬퍼 사용하기
특히 Hono의 RPC 기능을 사용하거나 잘 정의된 경로 스키마가 있는 경우, 더 나은 타입 안전성을 위해 Hono는 testClient
헬퍼(hono/testing
에서 제공)를 제공합니다. 이 클라이언트는 Hono 애플리케이션의 경로를 기반으로 타입이 지정되어 테스트에서 자동 완성 및 타입 검사를 제공합니다.
testClient 타입 추론에 대한 중요 참고 사항:testClient
가 타입을 올바르게 추론하려면 Hono 인스턴스에서 직접 체인 메서드를 사용하여 경로를 정의하거나(예: const app = new Hono().get(...).post(...)
), RPC를 사용하는 경우 경로 타입을 내보내야 합니다. 경로를 별도로 정의하면(예: const app = new Hono(); app.get(...)
) testClient
에 대한 타입 추론이 제한될 수 있습니다.
// src/app-for-test-client.ts
// testClient를 시연하기 위해 체인 경로가 있는 앱을 정의해 봅시다
import { Hono } from 'hono'
import { zValidator } from '@hono/zod-validator' // 타입 지정 쿼리 매개변수 예제
import { z } from 'zod'
const appWithChainedRoutes = new Hono()
.get('/search',
zValidator('query', z.object({ q: z.string(), limit: z.coerce.number().optional() })),
(c) => {
const { q, limit } = c.req.valid('query')
return c.json({ query: q, limit: limit || 10, results: [`${q}에 대한 결과 1`, `${q}에 대한 결과 2`] })
}
)
.post('/submit',
zValidator('json', z.object({ name: z.string(), email: z.string().email() })),
async (c) => {
const data = c.req.valid('json')
return c.json({ message: `${data.name}에 대한 데이터 수신!`, data }, 201)
}
);
export default appWithChainedRoutes;
// src/app-for-test-client.test.ts
import { describe, expect, it } from 'bun:test'
import { testClient } from 'hono/testing'
import appWithChainedRoutes from './app-for-test-client' // 앱 가져오기
describe('testClient가 있는 Hono 앱', () => {
const client = testClient(appWithChainedRoutes)
it('GET /search는 타입 지정 결과를 반환해야 함', async () => {
const res = await client.search.$get({
query: { q: 'hono rocks' }
})
expect(res.status).toBe(200)
const data = await res.json()
expect(data.query).toBe('hono rocks')
expect(data.results.length).toBeGreaterThan(0)
})
it('limit이 있는 GET /search는 이를 따라야 함', async () => {
const res = await client.search.$get({
query: { q: 'limit이 있는 hono', limit: '5' } // 쿼리 매개변수는 처음에 문자열
})
expect(res.status).toBe(200)
const data = await res.json()
expect(data.limit).toBe(5) // Zod 유효성 검사기가 숫자로 강제 변환
})
it('POST /submit는 유효한 데이터를 수락해야 함', async () => {
const payload = { name: '테스트 사용자', email: 'test@example.com' }
// JSON 본문이 있는 POST, PUT 등은 client.path.$post({ json: payload })와 같음
const res = await client.submit.$post({
json: payload
})
expect(res.status).toBe(201)
const data = await res.json()
expect(data.message).toBe(`${payload.name}에 대한 데이터 수신!`)
expect(data.data.email).toBe(payload.email)
});
it('헤더가 있는 POST /submit', async () => {
const payload = { name: '테스트 사용자 헤더', email: 'testheaders@example.com' }
const res = await client.submit.$post({
json: payload
}, {
headers: {
'X-Custom-Test-Header': 'Testing123'
}
})
expect(res.status).toBe(201)
// 일반적으로 이 헤더를 읽어 확인하는 경로/미들웨어가 있어야 함
});
})
이 테스트를 실행하려면 @hono/zod-validator
및 zod
가 설치되어 있다고 가정합니다 (bun add @hono/zod-validator zod
).
bun test src/app-for-test-client.test.ts
이 testClient
는 특히 정의된 스키마가 있는 API 테스트에 훨씬 더 나은 개발자 경험을 제공합니다.
결론
Hono는 속도, 경량 디자인 및 개발자 친화적인 기능의 조합으로 웹 개발에 대한 새로운 접근 방식을 제공합니다. 이 가이드에서는 시작하기 위한 기본 사항을 다루었지만 탐색할 내용이 훨씬 더 많습니다.
- 고급 라우팅 기법
- 더 복잡한 미들웨어 패턴
- JSX를 사용한 서버 측 렌더링
- 데이터베이스 통합
- Hono Client를 사용한 타입 안전 RPC 스타일 API
- 다양한 플랫폼에 배포
Hono 여정을 계속하면서 더 자세한 정보와 영감을 얻으려면 공식 문서 및 예제 저장소를 참조하세요.
웹 개발 환경은 끊임없이 진화하고 있으며, Hono는 웹 표준을 수용하고 성능을 우선시하며 성장하는 JavaScript 런타임 생태계 전반에서 작동하는 현대적인 접근 방식을 나타냅니다. 간단한 API를 구축하든 복잡한 애플리케이션을 구축하든 관계없이 Hono는 불필요한 오버헤드 없이 필요한 도구를 제공합니다.
작게 시작하고, 실험하며, 불꽃 같은 이름에 걸맞은 경량, 초고속 웹 프레임워크인 Hono와 함께 애플리케이션이 성장하는 것을 지켜보세요. 🔥
개발 팀이 최대 생산성으로 함께 작업할 수 있는 통합된 올인원 플랫폼을 원하십니까?
Apidog는 귀하의 모든 요구 사항을 충족하며 훨씬 저렴한 가격으로 Postman을 대체합니다!