Live data from Hacker News

Better HTTP server routing in Go 1.22

eli.thegreenplace.net

121–130 of 236 posts

Re: Better HTTP server routing in Go 1.22

#121

Earlier quoted context omitted.

You can't guarantee the order of registration will always be the same, so it's really undefined behavior. This is how the original ServeMux was designed and implemented, and they felt that was useful behavior to continue to support. From the design proposal[1]: > Using specificity for matching is easy to describe and > preserves the order-independence of the original ServeMux > patterns. But it can be hard to see at…

This seems like an issue caused by registration at a distance. I'm new to go and it is one of the things that felt most wrong. I'm used to a router where you define a big list of routes all in one place, maybe in some DSL. That's very easy to refactor, and doesn't have any ambiguity. If a library wants a route registered it puts a snippet in the docs for users to copy. Go in general seems to value clarity over magic…

Go's flag, log, image, and sql packages all work this way, so it's not just the HTTP router. I sort of see both sides. Having implicit registration makes it very easy to have different teams working on different packages and you just import the package and it registers itself. But it also makes the behavior of the resulting final binary hard to understand and based on implicit code instead of explicit. I personally try to just have one big routes() http.Handler function that returns everything all in one place, but I get why that isn't always practical.

Re: Better HTTP server routing in Go 1.22

#122
post #10

Forcing a panic when 2 routes are matched seems counter intuitive to me (versus, idk, every other web framework which uses the first-to-be-registered route that matches). Are there go-specific reasons for that? The edge case of "you might register HTTP routes in a bunch of places and it's harder to find that if multiple routes match" seems like something that be worked around with tooling. I've (ab)used the behavior…

I believe it allows `/foo/bar` and `/foo/{id}` as the first one is more specific and has precedence. This looks fine to me. Looks like it will panic in case you have `/foo/{id}/delete` and `/foo/bar/{action}`. /foo/bar/delete will match both, none is more specific so it panics. Feels reasonable. Having a first one wins precedence might be better though.

It's a 404 Not Found or 500 Server Error.

HTTP server panicking is never reasonable

Re: Better HTTP server routing in Go 1.22

#123
post #82

Earlier quoted context omitted.

You're joking, right? How is the second example better in any way? You're also doing more in your second example. You can still do service injection in JavaScript.

> You can still do service injection in JavaScript I know that angular is really good at this, but I'm not sure what pure js frameworks would allow a service to be defined as an interface first, and then injected into the constructor of a controller (or even a handler function) based on the implementation method selected somewhere else. I just haven't seen it happen.

tsyringe is a popular library that does this in TypeScript

Re: Better HTTP server routing in Go 1.22

#124
post #13

Earlier quoted context omitted.

> Are there go-specific reasons for that? In general , the reason you use a compiled / typed language like golang at all (instead of, say, perl) is to "left shift" your bugs: A bug caught when you first spin up your application is better than a bug caught after a corner case acts up in the wild, and a bug caught when you compile is better than a bug caught when you first spin up your application. I recently ran a cro…

Wouldn’t the “left-shift” be a compiler error instead of a panic?

Go as a language is generally not sophisticated enough to do that sort of thing.

A counter- and/or example of this is what Service Weaver does to try to bomb builds when generated files are older than their dependencies.

Re: Better HTTP server routing in Go 1.22

#125
post #118

Earlier quoted context omitted.

It’s not an exception. There is no magic. Large code bases are large, and not every program is your simple crud app with a handful of endpoints that can be meaningfully managed a single function.

Hard panic in a "not simple app with large codebase" app because you couldn't match a route is amateur hour.

I think you are vastly oversimplifying what has been said or why it works the way that it does. I really recommend you read the design document and reasoning, as it is rather clear why they are doing it the way that they are. If you have a cogent contribution to the discussion, please do share.

Re: Better HTTP server routing in Go 1.22

#126
post #93

Earlier quoted context omitted.

In order for code to be maintainable it first has to be readable. The second example has poor readability. And that's even before we get to the issue that this approach has fallen out of favor exactly because it result in code that can be a pain in the neck to figure out. Please don't do this. This is the kind of legacy approach that I try to teach people working for me NOT to follow.

> The second example has poor readability Only if you don't know C# or asp.net (or bootstrap). In which case: why would you be working for an organization which does? > And that's even before we get to the issue that this approach has fallen out of favor exactly because it result in code that can be a pain in the neck to figure out. This kind of structured approach has fallen out of favor because it's become more pop…

I personally find that the second example has poor readability even if you are familiar with the framework/pattern. I've worked on codebases that use each of those patterns, and I greatly prefer those where all of the routes (and ideally the auth middleware too) are defined in a single top-level routes file.

IMO it makes it much easier to get an overview of the overall functionality of the app, and to find the code which implements each route. It's also a lot more flexible if you ever need to support routes which do not fit the conventional pattern of the framework (perhaps for legacy reasons).

You can of course still use dependency injection, etc with this central route registration model.

Re: Better HTTP server routing in Go 1.22

#127
post #24

Earlier quoted context omitted.

The ownership transfer was publicly announced in quite a few places. Most notably gorilla's blog[0], but also on Reddit[1] as well as HN[2], though it didn't get much reaction on HN. [0] https://gorilla.github.io/blog/2023-07-17-project-status-upd... [1] https://www.reddit.com/r/golang/comments/1528e25/gorilla_web... [2] https://news.ycombinator.com/item?id=36935541

In my experience most developers are not connected to the development processes of their dependencies. Maybe they should be, I think there's an argument for it, but with so many dependencies there's only so much time and attention. I think any migration such as this should be done on the assumption that most people won't know it's happening.

It's a bit of a catch-22:

1. I want to send a PR!

2. Project doesn't seem very active, so never mind.

Plus I'm not checking if any of my dependencies need help every day.

I took over fsnotify after it was archived because I just didn't know they needed help. Last guy spent about 5 years looking for someone to take it over. I wouldn't have minded doing it before, but ... you do need to know about it.

Re: Better HTTP server routing in Go 1.22

#128

Earlier quoted context omitted.

> The second example has poor readability Only if you don't know C# or asp.net (or bootstrap). In which case: why would you be working for an organization which does? > And that's even before we get to the issue that this approach has fallen out of favor exactly because it result in code that can be a pain in the neck to figure out. This kind of structured approach has fallen out of favor because it's become more pop…

I personally find that the second example has poor readability even if you are familiar with the framework/pattern. I've worked on codebases that use each of those patterns, and I greatly prefer those where all of the routes (and ideally the auth middleware too) are defined in a single top-level routes file. IMO it makes it much easier to get an overview of the overall functionality of the app, and to find the code w…

I can understand that view, but I like to have the controller class files themselves represent the site hierarchy. Rather than looking in a file for the appropriate route, I look through the filesystem to understand the routing. I expect FooController to map to /foo (or /api/foo or whatever). I worked on a django project which did all the routing in a single location and it frequently resulted in merge conflicts between multiple developers committing changes to the file about the same time

Re: Better HTTP server routing in Go 1.22

#129

Earlier quoted context omitted.

Wouldn’t the “left-shift” be a compiler error instead of a panic?

Go as a language is generally not sophisticated enough to do that sort of thing. A counter- and/or example of this is what Service Weaver does to try to bomb builds when generated files are older than their dependencies.

I'm having trouble thinking of a mainstream production language with a stronger type system that could make a compile error out of the string argument passed to an HTTP router; can you think of one? Or of a non-string-typing for routes that solves the same problem, again in something people ordinarily use to deploy to production?

Re: Better HTTP server routing in Go 1.22

#130

Forcing a panic when 2 routes are matched seems counter intuitive to me (versus, idk, every other web framework which uses the first-to-be-registered route that matches). Are there go-specific reasons for that? The edge case of "you might register HTTP routes in a bunch of places and it's harder to find that if multiple routes match" seems like something that be worked around with tooling. I've (ab)used the behavior…

I would have expected the last one to override the first when registering routes. That seems to be the behavior I see most (not specific to web servers).

Given opposite expectations, erroring out makes sense, but a panic? Does that mean it crashes the whole web server when a client first accesses it, when you launch the server, or does it return a 500 to the client?

Post reply on HN