This is a breaking API change that changes how wildcard patterns are
treated. In particular, wildcards are no longer allowed to appear at
arbitrary places in the URL, and are only allowed to appear immediately
after a path separator. This change effectively changes the wildcard
sigil from "*" to "/*".
Users who use wildcard routes like "/hello*" will have to switch to
regular expression based routes to preserve the old semantics.
The motivation for this change is that it allows the router to publish a
special "tail" key which represents the unmatched portion of the URL.
This is placed into URLParams under the key "*", and includes a leading
"/" to make it easier to write sub-routers.
Instead of using struct embedding to build web.Mux, start moving towards
explicit mappings. This doesn't actually change the public API of
web.Mux, but feels a little cleaner to me.
The longer-term thing here is to get rid of the functions defined on
Muxes in the public documentation that are defined on "rt *Mux", which
is just plain ugly.
Previously, the middleware stack passed the router a C, but this was
both odd semantically (a pattern which mutated the environment might see
a *different* environment) and bad for perf: it cost us an allocation.
Now we only pass around *C's internally.
Importantly ("importantly"), this gets us down to 0 allocations for the
static routing case, and one allocation (the URLParams map) for the
normal routing case.
This change replaces a bit of API surface area (the Sub() method on Muxes) with
a slightly more expressive pattern syntax. I'm mostly doing this because it
seems cleaner: the "*" gets to take on a meaning very similar to what it means
in Sinatra (without growing regexp-like middle-of-a-path globbing, which sounds
terrifying and not particularly useful), and we get to nuke a useless function
from the API.
Add tests for both string and regular expression patterns. Also, reimplement
regexp.Regexp.Prefix() on top of the raw regexp/syntax representation, so we can
get a little more information out of regexps:
- Whether or not the regexp is left-anchored (at the beginning of the string)
- What the prefix of the regular expression is, even for left-anchored
expressions.
We do this by running the regular expression instructions ourselves, more or
less cargo-culting the original implementation from package regexp/syntax.
Unfortunately it's ~impossible to make this abstraction non-leaky, because the
regexp package doesn't give us information about whether or not it was
constructed using POSIX or Perl syntax, for example, or if the longest-match
setting was applied.
The upshot is that regexps are now probably pretty performant-ish. Maybe. (I
haven't actually benchmarked it).
They say that every programmer builds a web framework at some point. This one is
mine.
The basic idea behind this one is that I wanted a Sinatra for Go, and I couldn't
find one anywhere. Furthermore, net/http is in many ways really close to what I
want out of a Sinatra-in-Go, and many of the frameworks I did find seemed to
reinvent too much, or were incompatible with net/http in weird ways, or used too
much questionable reflection magic. So long story short, I wrote my own.
This implementation is only half-baked, and among other things it's missing a
whole lot of tests.