Routing with Hono — Taming the if-Chain
Hoplink's fetch handler has become a wall of if (request.method === ... && url.pathname ...) checks, and the new file routes will make it worse. A router turns that wall into a readable table of routes. On Workers the most popular choice is Hono, a small, fast framework built on the same web-standard Request and Response you already know.
The rule
One line per route: method, path pattern, handler.
import { Hono } from "hono";
const app = new Hono();
app.get("/:code", async (c) => {
const target = await c.env.LINKS.get(c.req.param("code"));
if (!target) return c.text("No such link", 404);
return c.redirect(target, 302);
});
app.post("/links", async (c) => {
const { code, url } = await c.req.json();
await c.env.LINKS.put(code, url);
return c.json({ created: code }, 201);
});
export default app;Reading it part by part:
app.get/app.postchoose the HTTP method."/:code"is a path pattern;:codecaptures whatever sits in that position, read withc.req.param("code").- The context
cbundles the request (c.req), your bindings (c.env) and response helpers (c.text,c.json,c.redirect). export default appworks because a Hono app already has thefetch(request, env, ctx)method the runtime expects.
Query strings stay separate from the path: for /links?owner=priya, the handler reads c.req.query("owner"). Keeping the two apart matters — the path says which thing, the query says how to filter or shape it.
Hono also supports middleware — functions that run before or after handlers. app.use("/admin/*", checkToken) guards every admin route with one line instead of repeating the check.
Itty Router is a still smaller alternative with the same route-table idea. And if you are shipping a full frontend (React, Svelte, Astro and friends), Cloudflare can serve its built files as static assets from the same Worker, with Hono handling the API routes beside them.
The shortcut
Write the route table first, as a comment, before any handler code. Then order it so specific paths come before catch-all patterns — routers try routes in the order you register them.
List the routes
POST /files,GET /files/:name,GET /:code,POST /links.
Trap: registering app.get("/:code") at the top. A later app.get("/stats") would never run, because stats is swallowed as a short code.
Drills
Answer fast — trust the rule.
In app.get("/:code", ...), how does the handler read the value of code?
Why can a Hono app be the default export of a Worker?
Inside a Hono handler, where are your KV, R2 and D1 bindings?
Routes are registered as GET /:code, then GET /stats. What does GET /stats do?
Every /admin/... route must check a token. What is the cleanest approach?
Remember
- One line per route: method, path pattern, handler.
- Shortcut: route table first, specific paths before catch-alls.
- Trap: a greedy
/:coderegistered early swallows later routes.
