Hono v4.3.0 is now available! Let's take a look at the new features.
Improve the RPC-mode
Thanks to @kosei28, @nakasyou, and @NamesMT, the RPC mode has been improved!
c.text()
is typed
The response of c.text()
was just a Response
object, not typed.
const routes = app.get('/about/me', (c) => {
return c.text('Me!') // the response is not typed
})
With this release, it will be a TypedResponse
and you can get the type within the client created by hc
.
const client = hc<typeof routes>('http://localhost:8787')
const res = await client.about.me.$get()
const text = await res.text() // text is typed as "Me!"
const json = await res.json() // json is never!
Support all JSON primitives
We added the tests for the responses of c.json()
to have the correct types and support inferring all primitives. The all tests below are passed!
const app = new Hono()
const route = app
.get('/api/string', (c) => c.json('a-string'))
.get('/api/number', (c) => c.json(37))
.get('/api/boolean', (c) => c.json(true))
.get('/api/generic', (c) => c.json(Math.random() > 0.5 ? Boolean(Math.random()) : Math.random()))
type AppType = typeof route
const client = hc<AppType>('http://localhost')
const stringFetch = await client.api.string.$get()
const stringRes = await stringFetch.json()
const numberFetch = await client.api.number.$get()
const numberRes = await numberFetch.json()
const booleanFetch = await client.api.boolean.$get()
const booleanRes = await booleanFetch.json()
const genericFetch = await client.api.generic.$get()
const genericRes = await genericFetch.json()
type stringVerify = Expect<Equal<'a-string', typeof stringRes>>
expect(stringRes).toBe('a-string')
type numberVerify = Expect<Equal<37, typeof numberRes>>
expect(numberRes).toBe(37)
type booleanVerify = Expect<Equal<true, typeof booleanRes>>
expect(booleanRes).toBe(true)
type genericVerify = Expect<Equal<number | boolean, typeof genericRes>>
expect(typeof genericRes === 'number' || typeof genericRes === 'boolean').toBe(true)
// using .text() on json endpoint should return string
type textTest = Expect<Equal<Promise<string>, ReturnType<typeof genericFetch.text>>>
Status code type
If you explicitly specify the status code, such as 200
or 404
, in c.json()
. It will be added as a type for passing to the client.
// server.ts
const app = new Hono().get(
'/posts',
zValidator(
'query',
z.object({
id: z.string()
})
),
async (c) => {
const { id } = c.req.valid('query')
const post: Post | undefined = await getPost(id)
if (post === undefined) {
return c.json({ error: 'not found' }, 404) // Specify 404
}
return c.json({ post }, 200) // Specify 200
}
)
export type AppType = typeof app
You can get the data by the status code.
// client.ts
const client = hc<AppType>('http://localhost:8787/')
const res = await client.posts.$get({
query: {
id: '123'
}
})
if (res.status === 404) {
const data: { error: string } = await res.json()
console.log(data.error)
}
if (res.ok) {
const data: { post: Post } = await res.json()
console.log(data.post)
}
// { post: Post } | { error: string }
type ResponseType = InferResponseType<typeof client.posts.$get>
// { post: Post }
type ResponseType200 = InferResponseType<typeof client.posts.$get, 200>
Improve compatibility with React
The compatibility of hono/jsx/dom
has been improved. Now, these React libraries work with hono/jsx/dom
!
The below demo is working with hono/jsx/dom
, not React.
If you want to use React libraries with hono/jsx/dom
, set-up tsconfig.json
and vite.config.ts
like the followings:
tsconfig.json
:
{
"compilerOptions": {
"paths": {
"react": ["./node_modules/hono/dist/jsx/dom"],
"react-dom": ["./node_modules/hono/dist/jsx/dom"]
}
}
}
vite.config.ts
:
import { defineConfig } from 'vite'
export default defineConfig({
resolve: {
alias: {
react: 'hono/jsx/dom',
'react-dom': 'hono/jsx/dom'
}
}
})
Thanks @usualoma!
createApp()
in Factory Helper
createApp()
method is added to Factory Helper. If you use this method with createFactory()
, you can avoid redundancy in the definition of the Env
type.
If your application is like this, you have to set the Env
in two places:
import { createMiddleware } from 'hono/factory'
type Env = {
Variables: {
myVar: string
}
}
// 1. Set the `Env` to `new Hono()`
const app = new Hono<Env>()
// 2. Set the `Env` to `createMiddleware()`
const mw = createMiddleware<Env>(async (c, next) => {
await next()
})
app.use(mw)
By using createFactory()
and createApp()
, you can set the Env only in one place.
import { createFactory } from 'hono/factory'
// ...
// Set the `Env` to `createFactory()`
const factory = createFactory<Env>()
const app = factory.createApp()
// factory also has `createMiddleware()`
const mw = factory.createMiddleware(async (c, next) => {
await next()
})
Deprecate serveStatic
for Cloudflare Workers
serveStatic
exported by hono/cloudflare-workers
has been deprecated. If you create an application which serves static asset files, use Cloudflare Pages instead.
Other features
- Cookie Helper - delete cookie returns the deleted value #2512
- Bearer Authenticate - add
headerName
option #2514 - JSX/DOM - preserve the state of element even if it is repeatedly evaluated by children #2563
- Mimes utility - expose built-in MIME types #2516
- Serve Static - expose serve-static builder #2515
- Secure Headers - enable to set nonce in CSP #2577
- Server-Timing - allow
crossOrigin
in TimingOptions to be a function #2359 - Client - add
init
option #2592
All Updates
- fix(request): infer params in a path includes one or more optional parameter by @yusukebe in #2576
- feat(rpc): Add status code to response type by @kosei28 in #2499
- feat(helper/cookie): delete cookie returns the deleted value by @sor4chi in #2512
- feat(bearer-auth): add
headerName
option by @eliasbrange in #2514 - feat(jsx/dom): improve compatibility with React by @usualoma in #2553
- fix(jsx): preserve the state of element even if it is repeatedly evaluated by children by @usualoma in #2563
- feat: expose built-in MIME types by @cometkim in #2516
- feat: expose serve-static builder by @cometkim in #2515
- feat(secure-headers): enable to set nonce in CSP by @usualoma in #2577
- chore(pr_template): Use Bun instead of yarn by @nakasyou in #2582
- feat(cloudflare-workers): deprecate
serveStatic
by @yusukebe in #2583 - feat(types): improve response types flow by @NamesMT in #2581
- docs(readme): remove Benchmarks section by @yusukebe in #2591
- feat: improve
ToSchema
&WebSocket Helper
types by @NamesMT in #2588 - feat(factory): add
createApp()
by @yusukebe in #2573 - feat(hc): add
init
option by @NamesMT in #2592 - feat(timing): allow crossOrigin in TimingOptions to be a function by @jonahsnider in #2359
- Next by @yusukebe in #2600
New Contributors
- @kosei28 made their first contribution in #2499
- @NamesMT made their first contribution in #2581
- @jonahsnider made their first contribution in #2359
Full Changelog: v4.2.9...v4.3.0