DIY server routing with URLPattern
I think URLPattern
is underrated in server-side JavaScript. Everyone ends up reinventing their own subtlety different route definition syntax.
Hono:
app.get('/user/:name', ...)
app.get('/post/:date{[0-9]+}/:title{[a-z]+}', ...)
app.get('/posts/:filename{.+\\.png}', ...)
router.get('/user/:id(\\d+)', ...)
router.get('/plantae/:genus.:species', ...)
They're all fine and great and all that, I just like the builtin-ness of URLPattern
.
Demo of URLPattern
in action:
const pattern = new URLPattern({ pathname: "/user/:name" })
const match = pattern.exec("https://example.org/user/Alan%20Turing")
//=> {
...
"pathname": {
"groups": { "name": "Alan%20Turing" },
"input": "/user/Alan%20Turing"
},
...
}
Here's how I've started using it to DIY my own rudimentary router for basic sketches without any dependencies:
// ⭐ Define your routes here. Order matters.
const routes = [
[new URLPattern({ pathname: "/" }), {
HEAD() { return this.GET(); },
GET() { return new Response("Visit /api/<thing> to see it happen"); },
}],
[new URLPattern({ pathname: "/api/:thing" }), {
HEAD(request, match) { return this.GET(request, match); },
GET(request, match) {
console.dir(request.url); //=> "https://localhost:8000/api/small-thing"
console.dir(match.pathname.groups.thing); //=> "small-thing"
// ... do the stuff with the thing
const { thing } = match.pathname.groups;
return new Response(`The thing is: ${thing}`);
},
}],
// ... more routes here
];
export default {
// 👨💻 Do the routing here.
async fetch(request) {
const route = routes
.values()
.map(([pattern, handlers]) => [pattern.exec(request.url), handlers])
.find(([match, handlers]) => !!match);
if (!route) return new Response(null, { status: 404 });
const [match, handlers] = route;
const handler = handlers[request.method];
if (!handler) return new Response(null, { status: 405 });
// Monkey around with pre/post middlewares here.
return await handler.call(handlers, request, match);
},
};
This works great for making easy copy-paste no-dependency demos in the Deno Deploy playground. I'm sure it also works great with the Cloudflare Workers playground too.
Sometimes you just want the most basic of basics.