Hono — это быстрый, легковесный веб-фреймворк, работающий везде, где поддерживается JavaScript, и построенный с использованием веб-стандартов. Конечно же, он работает на Cloudflare Workers.
Три года назад, в декабре 2021 года, я хотел создавать приложения для Cloudflare Workers, но код без использования фреймворка становился слишком многословным, и мне не удалось найти фреймворк, который бы отвечал моим требованиям. Itty-router был очень хорош, но слишком прост. Worktop и Sunder делали то, что я хотел, но их API мне не очень нравился. Мне также было интересно создать роутер на основе структуры Trie, так как это обеспечивает высокую скорость. Таким образом, я начал разрабатывать веб-фреймворк с роутером на базе Trie.
«Когда я пытался создать свои приложения, я в итоге создал фреймворк для них» — классический пример yak shaving. Однако сейчас Hono используется многими разработчиками, включая Cloudflare, который применяет Hono в своих основных продуктах. Поэтому это путешествие в дебри yak shaving оказалось действительно значимым.
Write once, run anywhere
Hono действительно работает везде, а не только на Cloudflare Workers. Позже в статье я расскажу, почему, но Hono также работает на Deno, Bun и Node.js. Это потому, что Hono не зависит от внешних библиотек, а использует только API веб-стандартов, поддерживаемых каждым из этих окружений.
Для разработчиков это радость — знать, что один и тот же код может работать в разных окружениях. Например, следующий код src/index.ts будет работать на Cloudflare Workers, Deno и Bun:
import { Hono } from 'hono'
const app = new Hono()
app.get('/hello', (c) => c.text('Hello Hono!'))
export default app
Чтобы запустить его на Cloudflare Workers, выполните команду Wrangler:
wrangler dev src/index.ts
Тот же код работает на Deno:
deno serve src/index.ts
И на Bun:
bun run src/index.ts
Это всего лишь простой пример “Hello World”, но более сложные приложения с использованием middleware и вспомогательных функций, о которых я расскажу ниже, также могут работать на Cloudflare Workers или других окружениях. В подтверждение этому почти весь наш тестовый код для Hono может выполняться одинаково во всех этих окружениях. Это настоящий опыт “написано один раз, работает везде”.
Кто использует Hono?
Hono сейчас используется многими разработчиками и компаниями. Например, Unkey разворачивает своё приложение, построенное с использованием функции OpenAPI Hono, на Cloudflare Workers. Ниже приведён список компаний, использующих Hono, по результатам моего опроса «Кто использует Hono в продакшене?»:
- Cloudflare
- Nodecraft
- OpenStatus
- Unkey
- Goens
- NOT A HOTEL
- CyberAgent
- AI shift
- Hanabi.rest
- BaseAI
Существует ещё множество компаний, не включённых в этот список. Крупные веб-сервисы и библиотеки, такие как Prisma, Resend, Vercel AI SDK, Supabase и Upstash, используют Hono в своих примерах. Также есть несколько инфлюенсеров, которые предпочитают Hono в качестве альтернативы Express.
Конечно же, в Cloudflare мы также используем Hono. D1 использует Hono для внутреннего веб-API, работающего на Workers. Workers Logs базируется на коде Baselime (компания была приобретена Cloudflare) и использует Hono для миграции приложений с их оригинальной инфраструктуры на Cloudflare Workers. Все внутренние или клиентские API Workers Logs работают на Workers с использованием Hono. Мы также используем Hono в рамках внутренностей многих других продуктов, таких как KV и Queues.
Почему создаётся «мульти-рантайм» фреймворк?
Может возникнуть вопрос: «Почему сотрудник Cloudflare создаёт фреймворк, который работает везде?» Изначально Hono был разработан для работы исключительно с Cloudflare Workers. Однако начиная с версии 2 я добавил поддержку Deno и Bun. Это было очень мудрое решение. Если бы Hono был нацелен только на Cloudflare Workers, он мог бы не привлечь столько пользователей. Благодаря возможности работать на разных рантаймах он получает больше пользователей, что приводит к обнаружению ошибок и получению большего количества отзывов, что в конечном итоге приводит к более качественному программному обеспечению.
Hono и Cloudflare — идеальное сочетание
Комбинация Hono и Cloudflare предлагает приятный опыт разработки.
Многие сайты, включая нашу документацию Cloudflare, представляют следующее “ванильное” JavaScript-решение в качестве “Hello World” для Cloudflare Workers:
export default {
fetch: () => {
return new Response('Hello World!')
}
}
Это примитивно и полезно для понимания принципов работы Workers. Однако если вы хотите создать конечную точку, которая «возвращает JSON-ответ на GET-запросы, приходящие на /books», вам нужно написать что-то вроде этого:
export default {
fetch: (req) => {
const url = new URL(req.url)
if (req.method === 'GET' && url.pathname === '/books') {
return Response.json({
ok: true
})
}
return Response.json(
{
ok: false
},
{
status: 404
}
)
}
}
Если использовать Hono, то код будет выглядеть так:
import { Hono } from 'hono'
const app = new Hono()
app.get('/books', (c) => {
return c.json({
ok: true
})
})
export default app
Он короткий, и вы можете интуитивно понять, что он обрабатывает GET-запросы на /books.
Если вы хотите обрабатывать GET-запросы к /authors/yusuke и получить «yusuke» из пути, где «yusuke» — это переменная, вам придётся добавить что-то более сложное в ванильном JavaScript:
if (req.method === 'GET') {
const match = url.pathname.match(/^\/authors\/([^\/]+)/)
if (match) {
const author = match[1]
return Response.json({
Author: author
})
}
}
Если использовать Hono, вам не нужны операторы if. Просто добавьте определение конечной точки в приложение. Также не нужно писать регулярное выражение, чтобы получить «yusuke». Вы можете получить его с помощью функции c.req.param():
app.get('/authors/:name', (c) => {
const author = c.req.param('name')
return c.json({
Author: author
})
})
Один или два маршрута могут быть в порядке, но если их больше, обслуживание становится сложнее. Код становится более запутанным, а ошибки труднее находить. Используя Hono, код получается очень аккуратным.
Также легко работать с привязками к продуктам Cloudflare, таким как KV, R2, D1 и т. д., так как Hono использует «модель контекста». Контекст — это контейнер, который хранит состояние приложения до получения запроса и отправки ответа. Вы можете использовать контекст для получения объекта запроса, установки заголовков ответа и создания пользовательских переменных. Контекст также содержит привязки Cloudflare. Например, если вы настроили пространство имён Cloudflare KV с именем MY_KV, вы можете получить доступ к нему следующим образом, с автодополнением типов в TypeScript:
import { Hono } from 'hono'
type Env = {
Bindings: {
MY_KV: KVNamespace
}
}
const app = new Hono<Env>()
app.post('/message', async (c) => {
const message = c.req.query('message') ?? 'Hi'
await c.env.MY_KV.put('message', message)
return c.text(`message is set`, 201)
})
Hono позволяет писать код простым и интуитивно понятным образом, но это не означает, что есть ограничения. С помощью Hono можно сделать всё, что возможно на Cloudflare Workers.