Back

Dicas para Portar uma Aplicação Express para o Hono

Dicas para Portar uma Aplicação Express para o Hono

Se você mantém uma API Express e está considerando migrar para o Hono, a primeira coisa que vale a pena entender é que esta não é uma migração de “localizar e substituir”. O Express é construído sobre o módulo http do Node e seus próprios objetos req/res. O Hono é construído sobre a Fetch API e os Web Standards. Essa diferença molda tudo: roteamento, middleware, tratamento de requisições e respostas.

Aqui está o que você precisa saber antes de começar.

Principais Conclusões

  • Express e Hono se apoiam em fundamentos fundamentalmente diferentes: o módulo http do Node versus a Fetch API e os Web Standards.
  • O Hono substitui os objetos separados req e res do Express por um único objeto de contexto c, e os handlers precisam retornar um Response.
  • As assinaturas de middleware diferem — o Express usa (req, res, next) enquanto o Hono usa (c, next) com um next() aguardado via await.
  • O parsing do corpo da requisição acontece diretamente dentro dos handlers do Hono, em vez de através de middleware global.
  • Uma migração incremental, começando com rotas JSON sem estado, é muito mais segura do que uma reescrita completa.

Entenda Primeiro a Diferença Arquitetural

O Express encapsula o IncomingMessage e o ServerResponse do Node. Cada objeto req e res é específico do Node. O Hono, em contraste, trabalha com objetos Request e Response padrão — os mesmos que você usaria em um navegador ou em um Cloudflare Worker.

Ao rodar o Hono no Node.js, você usa o adaptador @hono/node-server, que faz a ponte entre os dois mundos. Mas o handler em si permanece agnóstico em relação ao runtime.

// Express
app.get('/users/:id', async (req, res) => {
  const user = await db.findById(req.params.id)
  res.json(user)
})

// Hono
app.get('/users/:id', async (c) => {
  const user = await db.findById(c.req.param('id'))
  return c.json(user)
})

O formato é semelhante, mas c (o objeto de contexto) substitui tanto req quanto res. Você retorna um Response em vez de chamar métodos em res.

Migrando APIs Node.js para o Hono: Comece com Rotas Sem Estado

O lugar mais seguro para começar a portar aplicações Express para o Hono é com rotas sem estado, apenas JSON — sem acesso ao sistema de arquivos, sem streams específicos do Node, sem middleware de sessão. Essas se traduzem de forma limpa.

Rotas que dependem de APIs específicas do Node (req.socket, res.locals, res.sendFile) exigem mais reflexão. Isole-as primeiro, para saber com o que está lidando antes de se comprometer com uma migração completa.

Migração de Middleware no Hono: Não Assuma Compatibilidade

O middleware do Express segue o padrão (req, res, next). O middleware do Hono usa (c, next) e tipicamente chama await next(). Eles não são intercambiáveis.

// Middleware Express
app.use((req, res, next) => {
  req.startTime = Date.now()
  next()
})

// Equivalente Hono
app.use(async (c, next) => {
  c.set('startTime', Date.now())
  await next()
})

Para pacotes comuns, o Hono tem equivalentes oficiais:

ExpressEquivalente Hono
cors()hono/cors
helmet()hono/secure-headers
express.json()Embutido via c.req.json()
morganhono/logger ou um middleware customizado

Reescreva o middleware de forma intencional, em vez de tentar encapsular o middleware do Express — a abstração raramente se mantém de forma limpa.

Tratamento do Corpo da Requisição e Resposta

No Express 5, o parsing do corpo ainda é baseado em middleware. No Hono, você faz o parsing do corpo diretamente no handler:

// Parsing do corpo no Hono
app.post('/items', async (c) => {
  const body = await c.req.json()
  return c.json({ received: body }, 201)
})

As respostas são sempre retornadas, nunca mutadas. Não há res.status(201).json(...) — em vez disso, você passa o status como segundo argumento para c.json().

Tratamento de Erros

O Express usa um manipulador de erros com quatro argumentos (err, req, res, next). O Hono usa app.onError:

app.onError((err, c) => {
  console.error(err)
  return c.json({ error: 'Internal Server Error' }, 500)
})

Migre de Forma Incremental, Não Tudo de Uma Vez

Uma reescrita completa raramente corre bem. Uma abordagem melhor:

  1. Porte um grupo de rotas isolado de cada vez.
  2. Execute o Hono junto com o Express durante a transição.
  3. Reescreva o middleware explicitamente — não o encapsule.
  4. Deixe dependências específicas do Node (manipulação de arquivos, autenticação legada) por último.

Conclusão

Portar aplicações Express para o Hono é simples, uma vez que você aceite que os dois frameworks se apoiam em fundamentos diferentes. A sintaxe de roteamento é familiar o suficiente para que a maioria das rotas se traduza em minutos. O trabalho real está no middleware e em qualquer coisa que toque diretamente em APIs específicas do Node. Aborde essas partes com cuidado, e a migração se torna gerenciável.

FAQs

Sim. Um padrão comum é colocar um proxy reverso ou um pequeno ponto de entrada Node na frente de ambos, roteando caminhos específicos para a aplicação Hono e deixando o restante com o Express. Isso permite migrar grupos de rotas um de cada vez e fazer rollback rapidamente se algo quebrar, em vez de se comprometer com uma única transição arriscada.

O Hono roda no Node.js, Bun, Deno, Cloudflare Workers, AWS Lambda e vários outros runtimes. No Node, você usa o adaptador @hono/node-server para fazer a ponte entre o modelo da Fetch API e o módulo http do Node. O mesmo código de handler permanece portátil entre runtimes, o que é uma das principais vantagens do Hono sobre o Express.

Geralmente, não. O middleware do Express depende dos objetos req e res do Node e do callback next, enquanto o middleware do Hono opera em um contexto no estilo Fetch. Existem alguns adaptadores da comunidade, mas tendem a ser frágeis. A abordagem recomendada é reescrever o middleware contra a API do Hono, já que a maioria das necessidades comuns já tem equivalentes oficiais ou embutidos.

O Hono é geralmente mais rápido que o Express, particularmente para roteamento e respostas JSON, graças ao seu roteador leve e design baseado em Fetch. Os ganhos no mundo real dependem da sua carga de trabalho — consultas a banco de dados e chamadas externas geralmente dominam. Trate o desempenho como um efeito colateral útil da migração, não como o motivo principal, a menos que seus benchmarks mostrem que o overhead de roteamento é um gargalo real.

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers. Check our GitHub repo and join the thousands of developers in our community.

OpenReplay