Summer's Words

Twice Failed (HTTP) Negotiations

So, I've been wanting to re-do my site for a while now, and, like the good developer I am, I've been writing micro-frameworks instead, because the other 2000 didn't strike my fancy.

I Gave myself the following goals:

And set off.

First Negotiation: MiddleStack

The neat thing about middlewares, is that they can edit whats going in, whats going out, and have full control over what happens next. Sounds perfect to build an entire framework around!

As seen in the README:

import {route, middlestack} from "https://deno.land/x/middlestack/mod.ts";;
Deno.serve(middlestack([
    route('GET', '/', async (req: Request) => {
        return new Response("Hello world!")
    }),
]));

With route being a middleware factory. set_header and error_handler middlewares also available out of the box.

This is all fine and stuff, but there was a few problems:

HTTP has a lot of neat things, for example, OPTIONS to find out what you can do to a specific URL, or HEAD just to get the headers. To be able to support both, I'd need to know all possible pairs of URLs and methods. Not easy! So my goals changed:

Second Negotiation: Cruet

An absolute abomination of a code-base, but it gets the job done, somehow.

With this new codebase, you just provide a folder of routes, even stuff like /post/:id(\d+).ts, and those files will automatically have their functions read, and pulled into a routing function, dynamically loaded too, to reduce load times on Deno Deploy et al.

That might sound scary, and according to votes, you'd be 50% right! But as a benefit of this complicated pile of logic, HEAD is automatically generated from a GET, and OPTIONS is also automatically handled!

Negotiations to Come

But I felt like I was forgetting something, so I had a good long think, and then remembered, Content negotiation. Something I locked away deep in the recesses of my mind because of needing some mild thinking, but also because there is so many options.

Accept, which allows specifying desired file types, Accept-Language which is the same for languages, Device-Memory, Viewport-Width, Width, But then if people have incorrectly configured devices, you need to ignore Accept-Language as well.

Even if I add support in my router for all these options, on the server side, things arn't so great.

Dealing with json and html is easy, return json if json, pass through a template if you need html, but that is only 2 of the types, and my framework doesn't have any in-built templating. No MVC concepts here, just routes and only routes.

And then languages... I mean, I only publish in one (at the moment), but there is a strong desire to just have support for the feature regardless. 3 methods × 1.5 file types × 2 languages, we already end up with 9 routing entries for a single URL.

Perhaps a rich HTTP server cannot coexist with a simple framework. Perhaps there are solutions to join the two concepts. But that day is not today, I'm tired.