Release Notes
Hono v4.7.0 is now available!
This release introduces one helper and two middleware.
- Proxy Helper
- Language Middleware
- JWK Auth Middleware
Plus, Standard Schema Validator has been born.
Let's look at each of these.
Proxy Helper
We sometimes use the Hono application as a reverse proxy. In that case, it accesses the backend using fetch
. However, it sends an unintended headers.
app.all('/proxy/:path', (c) => {
// Send unintended header values to the origin server
return fetch(`http://${originServer}/${c.req.param('path')}`)
})
For example, fetch
may send Accept-Encoding
, causing the origin server to return a compressed response. Some runtimes automatically decode it, leading to a Content-Length
mismatch and potential client-side errors.
Also, you should probably remove some of the headers sent from the origin server, such as Transfer-Encoding
.
Proxy Helper will send requests to the origin and handle responses properly. The above headers problem is solved simply by writing as follows.
import { Hono } from 'hono'
import { proxy } from 'hono/proxy'
app.get('/proxy/:path', (c) => {
return proxy(`http://${originServer}/${c.req.param('path')}`)
})
You can also use it in more complex ways.
app.get('/proxy/:path', async (c) => {
const res = await proxy(
`http://${originServer}/${c.req.param('path')}`,
{
headers: {
...c.req.header(),
'X-Forwarded-For': '127.0.0.1',
'X-Forwarded-Host': c.req.header('host'),
Authorization: undefined,
},
}
)
res.headers.delete('Set-Cookie')
return res
})
Thanks @usualoma!
Language Middleware
Language Middleware provides 18n functions to Hono applications. By using the languageDetector
function, you can get the language that your application should support.
import { Hono } from 'hono'
import { languageDetector } from 'hono/language'
const app = new Hono()
app.use(
languageDetector({
supportedLanguages: ['en', 'ar', 'ja'], // Must include fallback
fallbackLanguage: 'en', // Required
})
)
app.get('/', (c) => {
const lang = c.get('language')
return c.text(`Hello! Your language is ${lang}`)
})
You can get the target language in various ways, not just by using Accept-Language
.
- Query parameters
- Cookies
Accept-Language
header- URL path
Thanks @lord007tn!
JWK Auth Middleware
Finally, middleware that supports JWK (JSON Web Key) has landed. Using JWK Auth Middleware, you can authenticate by verifying JWK tokens. It can access keys fetched from the specified URL.
import { Hono } from 'hono'
import { jwk } from 'hono/jwk'
app.use(
'/auth/*',
jwk({
jwks_uri: `https://${backendServer}/.well-known/jwks.json`,
})
)
app.get('/auth/page', (c) => {
return c.text('You are authorized')
})
Thanks @Beyondo!
Standard Schema Validator
Standard Schema provides a common interface for TypeScript validator libraries. Standard Schema Validator is a validator that uses it. This means that Standard Schema Validator can handle several validators, such as Zod, Valibot, and ArkType, with the same interface.
The code below really works!
import { Hono } from 'hono'
import { sValidator } from '@hono/standard-validator'
import { type } from 'arktype'
import * as v from 'valibot'
import { z } from 'zod'
const aSchema = type({
agent: 'string',
})
const vSchema = v.object({
slag: v.string(),
})
const zSchema = z.object({
name: z.string(),
})
const app = new Hono()
app.get(
'/:slag',
sValidator('header', aSchema),
sValidator('param', vSchema),
sValidator('query', zSchema),
(c) => {
const headerValue = c.req.valid('header')
const paramValue = c.req.valid('param')
const queryValue = c.req.valid('query')
return c.json({ headerValue, paramValue, queryValue })
}
)
const res = await app.request('/foo?name=foo', {
headers: {
agent: 'foo',
},
})
console.log(await res.json())
Thanks @muningis!
New features
- feat(helper/proxy): introduce proxy helper #3589
- feat(logger): include query params #3702
- feat: add language detector middleware and helpers #3787
- feat(hono/context): add buffer returns #3813
- feat(hono/jwk): JWK Auth Middleware #3826
- feat(etag): allow for custom hashing methods to be used to etag #3832
- feat(router): support greedy matches with subsequent static components #3888
All changes
- docs(CONTRIBUTING): remove text about
yarn
by @EdamAme-x in #3878 - refactor(request):
toLowerCase()
is unnecessary forreq.header()
by @yusukebe in #3880 - fix(helper/adapter): correct
env
type by @yusukebe in #3885 - chore(test): update to vitest 3 by @yasuaki640 in #3861
- fix(router/trie-router): fix label with trailing wildcard pattern by @usualoma in #3892
- feat(helper/proxy): introduce proxy helper by @usualoma in #3589
- feat(logger): include query params by @ryuapp in #3702
- feat(factory): Allow HonoOptions with factory by @miyaji255 in #3786
- feat: add language detector middleware and helpers by @lord007tn in #3787
- feat(hono/context): add buffer returns by @askorupskyy in #3813
- feat(hono/jwk): JWK Auth Middleware by @Beyondo in #3826
- feat(etag): allow for custom hashing methods to be used to etag by @EdamAme-x in #3832
- feat(router): support greedy matches with subsequent static components. by @usualoma in #3888
- fix(client): correct inferring empty object from
c.json({})
by @yusukebe in #3873 - Next by @yusukebe in #3896
- chore(runtime-tests): add
deno.lock
by @yusukebe in #3897
New Contributors
- @lord007tn made their first contribution in #3787
Full Changelog: v4.6.20...v4.7.0