모범 사례
Hono는 매우 유연한 프레임워크다. 여러분은 원하는 방식으로 앱을 작성할 수 있다. 하지만 지켜야 할 모범 사례가 존재한다.
가능하면 "컨트롤러"를 만들지 말자
가능한 경우 "Ruby on Rails 스타일의 컨트롤러"를 만들지 않는 것이 좋다.
ts
// 🙁
// RoR 스타일의 컨트롤러
const booksList = (c: Context) => {
return c.json('list books')
}
app.get('/books', booksList)이 방식은 타입과 관련된 문제를 일으킨다. 예를 들어, 복잡한 제네릭을 작성하지 않으면 컨트롤러에서 경로 매개변수를 추론할 수 없다.
ts
// 🙁
// RoR 스타일의 컨트롤러
const bookPermalink = (c: Context) => {
const id = c.req.param('id') // 경로 매개변수를 추론할 수 없음
return c.json(`get ${id}`)
}따라서 RoR 스타일의 컨트롤러를 만들 필요 없이, 경로 정의 바로 뒤에 핸들러를 작성하는 것이 더 좋다.
ts
// 😃
app.get('/books/:id', (c) => {
const id = c.req.param('id') // 경로 매개변수를 추론할 수 있음
return c.json(`get ${id}`)
})hono/factory의 factory.createHandlers()
RoR 스타일의 Controller를 만들고 싶다면, hono/factory의 factory.createHandlers()를 사용한다. 이 방식을 사용하면 타입 추론이 정상적으로 동작한다.
ts
import { createFactory } from 'hono/factory'
import { logger } from 'hono/logger'
// ...
// 😃
const factory = createFactory()
const middleware = factory.createMiddleware(async (c, next) => {
c.set('foo', 'bar')
await next()
})
const handlers = factory.createHandlers(logger(), middleware, (c) => {
return c.json(c.var.foo)
})
app.get('/api', ...handlers)더 큰 애플리케이션 구축하기
"Ruby on Rails 스타일의 컨트롤러"를 만들지 않고도 app.route()를 사용해 더 큰 애플리케이션을 구축할 수 있다.
애플리케이션에 /authors와 /books 엔드포인트가 있고, 이를 index.ts 파일과 분리하려면 authors.ts와 books.ts 파일을 생성한다.
ts
// authors.ts
import { Hono } from 'hono'
const app = new Hono()
app.get('/', (c) => c.json('작가 목록'))
app.post('/', (c) => c.json('작가 생성', 201))
app.get('/:id', (c) => c.json(`${c.req.param('id')} 조회`))
export default appts
// books.ts
import { Hono } from 'hono'
const app = new Hono()
app.get('/', (c) => c.json('책 목록'))
app.post('/', (c) => c.json('책 생성', 201))
app.get('/:id', (c) => c.json(`${c.req.param('id')} 조회`))
export default app그런 다음, 이 파일들을 임포트하고 app.route()를 사용해 /authors와 /books 경로에 마운트한다.
ts
// index.ts
import { Hono } from 'hono'
import authors from './authors'
import books from './books'
const app = new Hono()
// 😃
app.route('/authors', authors)
app.route('/books', books)
export default appRPC 기능을 사용하려면
위 코드는 일반적인 사용 사례에서 잘 작동한다. 하지만 RPC 기능을 사용하려면 다음과 같이 체이닝을 통해 올바른 타입을 얻을 수 있다.
ts
// authors.ts
import { Hono } from 'hono'
const app = new Hono()
.get('/', (c) => c.json('list authors'))
.post('/', (c) => c.json('create an author', 201))
.get('/:id', (c) => c.json(`get ${c.req.param('id')}`))
export default appapp의 타입을 hc에 전달하면 올바른 타입을 얻을 수 있다.
ts
import app from './authors'
import { hc } from 'hono/client'
// 😃
const client = hc<typeof app>('http://localhost') // 타입이 정확히 지정됨더 자세한 내용은 RPC 페이지를 참고한다.