Construye una API REST en 5 minutos con Hono: Adiós Express, Hola Velocidad
ximo
Autor
¿Sigues usando Express para tus nuevos proyectos en 2025? Tenemos que hablar.
No me malinterpretes. Express ha sido el abuelo venerable del backend en JavaScript durante más de una década. Nos enseñó todo lo que sabemos. Pero seamos honestos: se siente pesado. Su arquitectura se diseñó cuando «el Edge» era solo un guitarrista de U2 y no la forma más eficiente de distribuir software.
El desarrollo web ha cambiado. Ahora buscamos velocidad absurda, despliegues globales en milisegundos y, sobre todo, no tener que arrastrar una carpeta node_modules que pesa más que el propio sistema operativo.
Aquí es donde entra Hono.
Si has oído el runrún en Twitter (o X) y te preguntas si es puro marketing o si hay fuego real detrás del humo, estás en el lugar correcto. En este artículo, no vamos a divagar con teoría aburrida. Vamos a construir. Vas a pasar de «cero» a tener una API REST completamente funcional y optimizada en lo que tardas en tomarte un café.
Advertencia: Una vez que pruebas la velocidad de desarrollo (y de ejecución) de Hono, volver a escribir
app.use()en Express se sentirá como volver al acceso a internet por módem telefónico.
¿Por qué Hono y por qué ahora? (No es solo Hype)
Podrías pensar: «Genial, otro framework de JavaScript. Justo lo que necesitaba para mi fatiga mental».
Te entiendo. La fatiga de frameworks es real. Pero Hono no es «otro framework más». Es una respuesta necesaria a la evolución de la infraestructura moderna.
La mayoría de los frameworks backend (como Express o NestJS) fueron construidos asumiendo que tu código correría en un servidor tradicional con Node.js. Pero hoy en día, queremos correr nuestro código en Cloudflare Workers, Deno, Bun, Vercel Edge o AWS Lambda.
Hono es agnóstico. Le da igual dónde lo pongas. Funciona.
Estándares Web: El secreto de la portabilidad
Aquí está la salsa secreta. Hono está construido sobre Estándares Web (Web Standards).
¿Qué significa esto en cristiano? Que utiliza las APIs nativas Request y Response que ya existen en el navegador y en los entornos modernos. No se inventa sus propios objetos complejos ni capas de abstracción innecesarias.
Imagina que Express es un cargador propietario antiguo que solo funciona en un enchufe específico de tu casa. Hono es USB-C. Conectas y carga. En cualquier sitio.
La Tabla de la Verdad: Hono vs. La Vieja Guardia
Los números no mienten. Comparemos Hono con los sospechosos habituales para ver dónde estamos parados.
| Característica | Express | Fastify | Hono |
| Filosofía | «Old School» Node.js | Velocidad en Node | Ultrafast & Edge First |
| Tamaño del Bundle | Pesado (muchas dependencias) | Medio | Diminuto (< 14kb) |
| Arranque (Cold Start) | Lento (Malo para Serverless) | Mejor que Express | Instantáneo |
| Compatibilidad | Node.js | Principalmente Node.js | Cualquiera (Cloudflare, Bun, Deno) |
| Tipado (TypeScript) | Parcheado (@types/express) | Bueno | Nativo y de Primera Clase |
Si tu objetivo es construir una API monolítica gigante que viva en un VPS tradicional, Express sigue sirviendo. Pero si quieres construir microservicios, APIs serverless o simplemente te gusta que tu servidor responda en microsegundos, Hono gana por goleada.
Manos a la obra: Tu API corriendo en tiempo récord
Basta de charlas motivacionales. Vamos a picar código.
Para este tutorial, usaremos TypeScript (porque es 2025 y nos queremos a nosotros mismos) y recomendaremos Bun como entorno de ejecución. ¿Por qué Bun? Porque combinado con Hono, la velocidad es sencillamente ridícula.
¿No tienes Bun? No pasa nada. Hono corre igual de bien en Node.js, pero si quieres vivir la experiencia completa, dale una oportunidad a Bun.
El Stack de la Velocidad
Abre tu terminal. No te vayas a por café, porque esto termina antes de que te levantes de la silla.
Bash
# Si usas Bun (Recomendado 🔥)
bun create hono mi-api-hono
# Si eres fiel a Node/npm
npm create hono@latest mi-api-hono
El asistente te preguntará qué plantilla quieres usar. Elige bun (o nodejs si preferiste npm). Entra en la carpeta e instala las dependencias:
Bash
cd mi-api-hono
bun install # o npm install
Hola Mundo en 3 líneas
Abre el archivo src/index.ts. Lo que vas a ver es la definición de simplicidad. Borra todo lo que haya y escribe esto:
TypeScript
import { Hono } from 'hono'
const app = new Hono()
app.get('/', (c) => {
return c.text('¡Hola Mundo desde Hono! 🚀')
})
export default app
Ahora corre el servidor: bun run dev (o npm run dev).
Ve a http://localhost:3000. ¡Bum! Ya tienes un servidor web respondiendo. Sin configuraciones de Babel, sin webpack, sin dolores de cabeza.
Entendiendo el «Contexto» (La obsesión de Hono)
Aquí es donde la gente que viene de Express suele tropezar. Presta atención.
En Express, estás acostumbrado a ver esto:
app.get(‘/’, (req, res) => { … })
Tienes dos objetos: req (lo que entra) y res (lo que sale). En Hono, eso no existe. En Hono, solo tienes c.
¿Dónde están req y res? Conoce a la variable c
c significa Context. Es tu navaja suiza. Hono encapsula toda la información de la solicitud entrante y todas las herramientas para construir la respuesta en este único objeto.
Míralo así:
- ¿Quieres leer un header? Usas
c. - ¿Quieres leer un parámetro de la URL? Usas
c. - ¿Quieres devolver un JSON? Usas
c.
JSON, Texto y Headers: Todo en un solo lugar
Veamos cómo se maneja esto en la vida real. Observa cómo todo fluye a través del contexto.
TypeScript
app.get('/usuario/:id', (c) => {
// 1. Leer parámetros de la ruta (INPUT)
const id = c.req.param('id')
// 2. Leer query params (ej: ?format=full)
const format = c.req.query('format')
// 3. Leer headers
const userAgent = c.req.header('User-Agent')
// 4. Devolver una respuesta JSON (OUTPUT)
// ¡OJO! En Hono siempre debes hacer RETURN
return c.json({
mensaje: 'Usuario encontrado',
userId: id,
formato: format || 'standard',
navegador: userAgent
}, 200) // El status code es opcional, 200 es default
})
Diferencia Crítica con Express: En Hono, debes retornar (return) la respuesta. Si no lo haces, tu endpoint se quedará colgado.
El Core: Construyendo un CRUD Real (Sistema de Libros)
Vamos a construir un CRUD completo para una biblioteca de libros. Usaremos un array en memoria para mantener el ejemplo puro.
Primero, define tu tipo de dato al principio de tu archivo src/index.ts:
TypeScript
type Book = {
id: string
title: string
author: string
}
const books: Book[] = [
{ id: '1', title: 'Clean Code', author: 'Robert C. Martin' },
{ id: '2', title: 'The Pragmatic Programmer', author: 'Andy Hunt' }
]
1. Rutas GET: Leyendo datos (Read)
Vamos a crear dos rutas: una para ver todos los libros y otra para buscar uno específico.
TypeScript
// Obtener todos los libros
app.get('/books', (c) => {
return c.json(books)
})
// Obtener un libro por ID
app.get('/books/:id', (c) => {
const id = c.req.param('id')
const book = books.find((b) => b.id === id)
if (!book) {
// 404 Not Found
return c.json({ message: 'Libro no encontrado' }, 404)
}
return c.json(book)
})
2. Ruta POST: Creando datos (Create)
Aquí viene la trampa clásica de los novatos. Leer el cuerpo de la petición (body) es una operación asíncrona. Tienes que usar await.
TypeScript
// Crear un nuevo libro
app.post('/books', async (c) => {
const body = await c.req.json() // <--- ¡OJO al await!
const newBook: Book = {
id: String(books.length + 1),
title: body.title,
author: body.author
}
books.push(newBook)
// 201 Created: El estándar para creación exitosa
return c.json(newBook, 201)
})
3. Rutas PUT y DELETE: Modificando la realidad
TypeScript
// Actualizar un libro (PUT)
app.put('/books/:id', async (c) => {
const id = c.req.param('id')
const body = await c.req.json()
const index = books.findIndex((b) => b.id === id)
if (index === -1) {
return c.json({ message: 'Libro no encontrado' }, 404)
}
// Actualizamos
books[index] = { ...books[index], ...body }
return c.json(books[index])
})
// Borrar un libro (DELETE)
app.delete('/books/:id', (c) => {
const id = c.req.param('id')
const index = books.findIndex((b) => b.id === id)
if (index === -1) {
return c.json({ message: 'Libro no encontrado' }, 404)
}
const deletedBook = books.splice(index, 1)
return c.json(deletedBook[0])
})
Middleware: Baterías incluidas, cero «bloatware»
Si vienes de Express, no necesitas instalar morgan o cors. Hono trae todo eso nativo.
Los imprescindibles: Logger, CORS y Pretty JSON
Añade esto justo después de iniciar tu app:
TypeScript
import { logger } from 'hono/logger'
import { cors } from 'hono/cors'
import { prettyJSON } from 'hono/pretty-json'
// ...
app.use('*', logger()) // Loguea cada petición
app.use('*', cors()) // Habilita CORS
app.use('*', prettyJSON()) // JSON legible con ?pretty
Creando tu propio Middleware (Tiempo de Respuesta)
TypeScript
// Middleware para medir tiempo de ejecución (X-Response-Time)
app.use('*', async (c, next) => {
const start = Date.now()
await next() // Pasa el control a tu ruta
const ms = Date.now() - start
c.header('X-Response-Time', `${ms}ms`)
})
Subiendo el Nivel: Validación de Datos con Zod
La regla número uno del backend: Nunca confíes en lo que te envía el usuario.
Usaremos Zod y el validador oficial de Hono. Instala el paquete:
Bash
bun add zod @hono/zod-validator
zod-validator: Validación automática y limpia
Refactorizamos la ruta POST para que sea imposible crear un libro inválido.
TypeScript
import { z } from 'zod'
import { zValidator } from '@hono/zod-validator'
// 1. Definimos el esquema
const bookSchema = z.object({
title: z.string().min(3, "El título debe tener al menos 3 letras"),
author: z.string().min(3, "El autor es obligatorio")
})
// 2. Inyectamos el validador
app.post('/books', zValidator('json', bookSchema), async (c) => {
// 3. Obtenemos los datos YA validados y tipados
const data = c.req.valid('json')
const newBook: Book = {
id: String(books.length + 1),
title: data.title,
author: data.author
}
books.push(newBook)
return c.json(newBook, 201)
})
Despliegue: Del Localhost al Edge (Cloudflare Workers)
Vamos a desplegar esto en Cloudflare Workers. Es gratis, global y se lleva de maravilla con Hono.
- Login en Cloudflare:bunx wrangler login
- Despliegue:bun run deploy
Verás algo así en tu terminal:
Plaintext
Uploaded mi-api-hono (0.55 sec)
Published mi-api-hono (0.20 sec)
https://mi-api-hono.tu-usuario.workers.dev
Entra en esa URL. Tu API ya está viva, tiene HTTPS automático y responde más rápido que tu sombra. Bienvenido al Edge Computing.
Preguntas Frecuentes sobre Hono (FAQ)
¿Hono funciona con bases de datos SQL como Postgres o MySQL?
Absolutamente. Si estás en Cloudflare Workers, usa Neon (Serverless Postgres) o Cloudflare D1. Si estás en Node.js, usa cualquier ORM como Prisma o Drizzle.
¿Puedo usar Hono si solo sé Node.js?
Sí. Hono tiene un «adaptador» para Node.js. Puedes escribir tu código en Hono y correrlo en un servidor Node tradicional sin problemas.
¿Es Hono compatible con librerías de Express?
No directamente, ya que los middlewares son diferentes. Sin embargo, el ecosistema de Hono ya ha portado casi todo lo necesario (JWT, Auth, Validaciones).
Conclusión: Tu siguiente paso
Acabas de ver cómo se construye el backend moderno.
- Menos código.
- Tipado estático real.
- Velocidad absurda.
- Despliegue global en segundos.
Express cumplió su misión, pero aferrarse a él hoy es como seguir usando jQuery cuando existe React. La web ha evolucionado hacia los estándares y el Edge, y Hono es el vehículo para llegar ahí.
¿El reto? No me creas. Toma el código de este artículo, ejecútalo y mira los tiempos de respuesta. Luego, intenta volver a escribir const express = require('express') sin sentir que estás viajando al pasado.
Te veo en el Edge. 🚀