Разработка бэкенда сайта на Node.js (Hono)
Hono — один из немногих фреймворков, написанных для работы на нескольких runtime одновременно: Node.js, Deno, Bun, Cloudflare Workers, AWS Lambda Edge. Один код — несколько платформ без адаптеров. Это главная причина его выбирать, когда проект может жить на edge или нужна гибкость по платформе.
Второй аргумент — производительность. Hono использует RegExpRouter — один из быстрейших алгоритмов маршрутизации: O(1) для статических маршрутов, O(n) для параметрических. На Bun обгоняет Fastify в benchmark'ах.
Базовая структура приложения
import { Hono } from 'hono'
import { cors } from 'hono/cors'
import { logger } from 'hono/logger'
import { prettyJSON } from 'hono/pretty-json'
import { secureHeaders } from 'hono/secure-headers'
const app = new Hono()
// Встроенные middleware
app.use('*', logger())
app.use('*', secureHeaders())
app.use('/api/*', cors({
origin: process.env.ALLOWED_ORIGINS?.split(',') ?? '*',
credentials: true
}))
// Обработка ошибок
app.onError((err, c) => {
console.error(err)
return c.json({ error: err.message }, 500)
})
app.notFound((c) => c.json({ error: 'Not found' }, 404))
export default app
Роутинг и группировка
import { Hono } from 'hono'
import { zValidator } from '@hono/zod-validator'
import { z } from 'zod'
const products = new Hono()
const createProductSchema = z.object({
name: z.string().min(2).max(255),
price: z.number().positive(),
categoryId: z.number().int()
})
products.get('/', async (c) => {
const { page = '1', limit = '20' } = c.req.query()
const db = c.get('db')
const items = await db.query(
'SELECT * FROM products LIMIT $1 OFFSET $2',
[Number(limit), (Number(page) - 1) * Number(limit)]
)
return c.json(items.rows)
})
products.post('/',
zValidator('json', createProductSchema),
async (c) => {
const body = c.req.valid('json') // полностью типизировано
const db = c.get('db')
// ...
return c.json({ id: newProduct.id }, 201)
}
)
products.get('/:id', async (c) => {
const id = c.req.param('id')
// ...
})
// Монтирование с префиксом
const api = new Hono().basePath('/api/v1')
api.route('/products', products)
api.route('/users', users)
app.route('', api)
Аутентификация через JWT
import { jwt } from 'hono/jwt'
import { getCookie, setCookie } from 'hono/cookie'
const authMiddleware = jwt({
secret: process.env.JWT_SECRET!,
cookie: 'access_token' // поддерживает JWT из cookie
})
// Защищённые маршруты
const protected = new Hono()
protected.use('*', authMiddleware)
protected.get('/profile', (c) => {
const payload = c.get('jwtPayload') // типизированный payload
return c.json({ userId: payload.sub })
})
// Login endpoint
app.post('/auth/login', zValidator('json', loginSchema), async (c) => {
const { email, password } = c.req.valid('json')
const user = await UserService.verifyCredentials(email, password)
if (!user) return c.json({ error: 'Invalid credentials' }, 401)
const token = await sign({ sub: user.id, role: user.role }, process.env.JWT_SECRET!)
setCookie(c, 'access_token', token, {
httpOnly: true,
secure: true,
sameSite: 'Strict',
maxAge: 60 * 60 * 24 * 7
})
return c.json({ user: { id: user.id, email: user.email } })
})
Middleware и context
Hono использует c.set() / c.get() для передачи данных через middleware — аналог ctx.state в Koa:
// Подключение БД через middleware
app.use('*', async (c, next) => {
c.set('db', pgPool)
await next()
})
// Типизация переменных контекста
type Env = {
Variables: {
db: Pool
user: { id: number; role: string }
}
}
const app = new Hono<Env>()
Edge-деплой на Cloudflare Workers
Одно из ключевых преимуществ Hono — деплой на Cloudflare Workers без изменений кода:
// wrangler.toml
// name = "my-api"
// compatibility_date = "2024-01-01"
// src/index.ts — тот же код
export default app // Hono совместим с Workers
// Доступ к Workers KV, D1, R2 через bindings
app.get('/cache/:key', async (c) => {
const kv = c.env.MY_KV // Cloudflare KV namespace
const value = await kv.get(c.req.param('key'))
return value ? c.text(value) : c.notFound()
})
Это полезно для API, которые должны работать с минимальной задержкой по всему миру — CDN-edge вместо одного дата-центра.
RPC-клиент
Hono поддерживает типизированный клиент — фронтенд получает типы из серверного кода без отдельной схемы:
// server/routes/users.ts
const users = new Hono()
.get('/', ..., (c) => c.json({ users: [] }))
.post('/', ..., (c) => c.json({ id: 1 }, 201))
export type UsersRoutes = typeof users
// client/api.ts (Next.js, React и т.д.)
import { hc } from 'hono/client'
import type { UsersRoutes } from '../server/routes/users'
const client = hc<UsersRoutes>('http://localhost:3000')
const res = await client.users.$get()
const data = await res.json() // полностью типизированный ответ
Когда использовать Hono
Hono хорошо подходит для: API с возможным edge-деплоем, проектов с TypeScript от начала, BFF (Backend For Frontend) слоя рядом с React/Next.js, микросервисов с минимальным footprint. Менее подходит для: сложных монолитов с богатым ORM, проектов с устоявшейся Express/Koa экспертизой в команде.
Сроки разработки
- Настройка проекта + базовые маршруты — 2–3 дня
- Auth + валидация — 3–5 дней
- Бизнес-логика — 1–3 недели в зависимости от объёма
- Edge-деплой и конфигурация Cloudflare — 2–4 дня дополнительно
Hono — быстрый старт с хорошей типизацией. Для небольшого API сайта полный цикл: 3–6 недель.







