Hono Integration
Using UnRAG with Hono for lightweight, fast APIs on Node.js or edge runtimes.
Hono is a lightweight web framework that works across Node.js, Bun, Deno, and Cloudflare Workers. When running on Node.js or Bun with standard Postgres drivers, UnRAG integrates seamlessly. For edge runtimes, you'll need compatible database drivers.
Basic setup on Node.js
On Node.js or Bun, UnRAG's default adapters work out of the box:
import { Hono } from "hono";
import { createUnragEngine } from "@unrag/config";
const app = new Hono();
app.get("/api/search", async (c) => {
const query = c.req.query("q")?.trim();
if (!query) {
return c.json({ error: "Missing query parameter" }, 400);
}
const engine = createUnragEngine();
const result = await engine.retrieve({ query, topK: 10 });
return c.json({
query,
results: result.chunks.map((chunk) => ({
id: chunk.id,
content: chunk.content,
source: chunk.sourceId,
score: chunk.score,
})),
});
});
app.post("/api/ingest", async (c) => {
const body = await c.req.json().catch(() => null);
if (!body?.sourceId || !body?.content) {
return c.json({ error: "Missing sourceId or content" }, 400);
}
const engine = createUnragEngine();
const result = await engine.ingest({
sourceId: body.sourceId,
content: body.content,
metadata: body.metadata ?? {},
});
return c.json({
documentId: result.documentId,
chunkCount: result.chunkCount,
});
});
export default app;Run with Node.js, Bun, or Deno (with Node compatibility):
# With Bun
bun run --hot src/index.ts
# With Node.js (using tsx)
npx tsx src/index.tsInput validation with Zod
Hono works well with Zod for request validation:
import { Hono } from "hono";
import { zValidator } from "@hono/zod-validator";
import { z } from "zod";
import { createUnragEngine } from "@unrag/config";
const app = new Hono();
const searchSchema = z.object({
q: z.string().min(2).max(500),
topK: z.coerce.number().min(1).max(50).default(10),
scope: z.string().optional(),
});
app.get(
"/api/search",
zValidator("query", searchSchema),
async (c) => {
const { q, topK, scope } = c.req.valid("query");
const engine = createUnragEngine();
const result = await engine.retrieve({
query: q,
topK,
scope: scope ? { sourceId: scope } : undefined,
});
return c.json({
query: q,
results: result.chunks,
meta: { embeddingModel: result.embeddingModel },
});
}
);
const ingestSchema = z.object({
sourceId: z.string().min(1),
content: z.string().min(1),
metadata: z.record(z.unknown()).optional(),
});
app.post(
"/api/ingest",
zValidator("json", ingestSchema),
async (c) => {
const { sourceId, content, metadata } = c.req.valid("json");
const engine = createUnragEngine();
const result = await engine.ingest({ sourceId, content, metadata });
return c.json(result);
}
);Edge runtime considerations
UnRAG's default adapters use the pg driver, which relies on Node.js APIs not available in edge runtimes (Cloudflare Workers, Vercel Edge). If you're deploying to edge, you have options:
Option 1: Use an edge-compatible Postgres driver
Neon's serverless driver works in edge environments:
import { neon } from "@neondatabase/serverless";
// You'll need a custom store adapter that uses neon()Option 2: Proxy to a Node.js backend
Keep UnRAG operations in a Node.js service and call it from your edge function:
// Edge function
app.get("/api/search", async (c) => {
const query = c.req.query("q");
// Forward to your Node.js backend
const response = await fetch(`${BACKEND_URL}/api/search?q=${query}`);
return c.json(await response.json());
});Option 3: Use a different vector database
Some vector databases (like Pinecone or Upstash Vector) offer edge-compatible SDKs. Build a custom store adapter for them.
Middleware for common patterns
Hono's middleware system lets you add cross-cutting concerns:
import { Hono } from "hono";
import { cors } from "hono/cors";
import { logger } from "hono/logger";
import { timing } from "hono/timing";
const app = new Hono();
// Enable CORS for frontend access
app.use("/api/*", cors());
// Log requests
app.use("*", logger());
// Add server timing headers
app.use("*", timing());
// Your routes
app.get("/api/search", async (c) => {
// ...
});Error handling
Wrap operations in try-catch and return appropriate responses:
import { HTTPException } from "hono/http-exception";
app.get("/api/search", async (c) => {
const query = c.req.query("q");
if (!query) {
throw new HTTPException(400, { message: "Missing query" });
}
try {
const engine = createUnragEngine();
const result = await engine.retrieve({ query, topK: 10 });
return c.json(result);
} catch (error) {
console.error("Search failed:", error);
throw new HTTPException(500, { message: "Search failed" });
}
});
// Global error handler
app.onError((err, c) => {
if (err instanceof HTTPException) {
return c.json({ error: err.message }, err.status);
}
return c.json({ error: "Internal server error" }, 500);
});Deployment patterns
Hono apps can deploy to many platforms:
- Bun:
bun run src/index.ts - Node.js: Use
@hono/node-serveradapter - Deno:
deno run --allow-net src/index.ts - Cloudflare Workers: Use
wrangler deploy(edge-compatible driver needed) - AWS Lambda: Use
@hono/aws-lambdaadapter
For Node.js deployments where UnRAG works best, the integration is straightforward. For edge deployments, plan for the driver compatibility issues ahead of time.