Show HN: A simple Go web server with logging, tracing, health check
gist.github.com
gist.github.com
Edit: found this https://gist.github.com/kennwhite/f9ea1afff776049974678fb21a...
https://beego.me and https://iris-go.com are nice, but we (all) have (as yet) to find a Django-like framework that comes with an extensible back-office.
So... Any pointers on the latter? I can do an Ask HN, but this seems like a good context to ask in.
(Edited to add: why the downvotes? Is this not a legitimate question?)
- julienschmidt/httprouter [1] for routing,
- jmoiron/sqlx [2] for SQL access, and
- gorilla/websocket [3] for websockets
sqlx isn't an ORM; it's more a convenience wrapper around the standard library's database/sql package.
gorm is the nicest ORM I've found, but I think even the well-written ORM packages are unnatural to use because of restrictions in Go's type system.
(Sorry if this isn't the kind of answer you were hoping for.)
[1] https://github.com/julienschmidt/httprouter
See the drama unfold at https://www.reddit.com/r/golang/comments/57w79c/why_you_real... and https://www.reddit.com/r/golang/comments/57tmp1/why_you_shou...
https://github.com/fragmenta/fragmenta
It’s fairly simple to write some simple generator using the built in text/template package if all you want are admin scaffolds.
People like go for its minimalist approach. Not in the sense that you don't have a lot of code to write, but more in the sense that you are in control of everything that happens, and that you can read an understand every part of your codebase.
ORMs , code gen, magic wrappers, etc is something that people in that community just hate.
Mostly agree except for code-gen --- definitely not so in the real world! I'd say most Gophers on the whole at a minimum don't mind it, and many either outright ---or eventually--- embrace it.
Depends on the nature and purpose(s) of the Go code-base but for many, it's as natural and idiomatic as is the extensive use of the macro preprocessor for many-perhaps-most grown, matured, "non-trivial" C code-bases. (Just fewer pitfalls in exchange for a bit more set-up effort.)
Elixir is close to my ideal though I like static types and a better community around libs would be nice.
The good side to it being simple to understand and maintain is that you won't pay a lot of debt if you're adding it to your stack.
There isn't a single language that fits all use case perfectly anyway, so we'd have to just go to the "best tool for the job" approach in the meantime.
Care to extend upon why you don't feel go is a good fit for other programming?
Which means the server side would need a way to wrap the db for graphql (along with a way to set up authorization), and the front-end would need to be able to discover/generate the crud parts.
If you really want a "legacy"/"traditional" framework (fat appserver handling form input, rendering html, talking to db backend), I think the mature ones will be hard to beat (eg: django).
https://gist.github.com/tomwhoiscontrary/b4888b86057c74a636c...
The main takeaway is that the JDK's built-in web server is poor:
* There is no way to configure timeouts
* Filters have to be added to each handler separately, by mucking with its filter list
* Filters have to extend an abstract class with two methods (one totally pointless), so you can't use lambdas for them
* Handlers use a simple string prefix match, so a request for "/healthzone" will hit the health handler
* The stop method always blocks for the specified timeout, and never returns early as the docs promise (IME)
Other minor irritations:
* There is no method to parse an InetSocketAddress from a string
* Java's support for handling clean process shutdown is not great; i think there's some sort of race between the shutdown hook and the logging system getting shut down, so you never see the "Server stopped" message
Twitter, Soundcloud, Salesforce, Pinterest, FitBit, Tumblr, Box, Foursquare... What do they all have in common? They all run finagle in production. For java, it is about as battletested and as good as you'll get unless you want to write your own. Personally, I'm more of a golang and python developer, but respect where it is due. Twitter is massively more scalable than the overwhelmingly majority of the sites on the internet and they've gotten their act together since abandoning Ruby and the fail whale.
Pick two.
> There is no way to configure timeouts
They're configured by properties if I recall.
> Filters have to be added to each handler separately, by mucking with its filter list
I personally prefer the explicitness of this.
As for the rest... I think a lot of these issues stem from the fact it's an old, not particularly well-known API in the JDK.
* serving of files and directories
* LetsEncrypt certificates and SSL
package main
import (
"fmt"
"net/http"
"path/filepath"
)
var (
host = "0.0.0.0"
path = "/var/www/public"
port = 8080
)
func main() {
path, err := filepath.Abs(path)
if err != nil {
panic(err)
}
listenAt := fmt.Sprintf("%s:%v", host, port)
fmt.Println("static-serve-dir serving", path, "over http at", listenAt)
err = http.ListenAndServe(listenAt, http.FileServer(http.Dir(path)))
if err != nil {
panic(err)
}
}Same thing!
I build stuff like this for a living. I'd recommend not re-inventing the wheel yourself and using a nice web framework, like Echo (https://github.com/labstack/echo) or Gin (https://github.com/gin-gonic/gin). I prefer Echo due to a cleaner, mockable design, but they're equivalent.
You can throw up that web server in 1/10 the code to do the same thing, and using built-in middleware is less work than writing your own.
I don't care for Gin. I'll take a look at Echo.
It has HTML templates library, decent error handling, rpc, logging, built-in http server. Many people choose golang for that reason.
Or do you mean single page JavaScript web sites? At which point Go would be the backing API? I don't see what qualifies Go for "small scale" vs "large scale."
Thanks for any clarification. Cheers!
A larger project is more likely to require features provided by third-party packages.
Go was not designed for the small scale, but the large:
- it has a sensible module system that makes compilation fast
- it's a simple language that encourages boring code - your coworkers will probably write code that works and that you can maintain
- Multithreading is a first class concept. Programs you build locally using typical patterns scale when you run them on massive multi-core servers
- the language is memory safe by default
C++ projects require experts to build, scale and maintain. Go is designed to give that capability to journeyman developers.
Yes C++ is generally going to be faster, but rarely do people talk about why that is. It usually comes down to: a smarter compiler, unsafe operations, or clever optimization. The first is legitimate, but rarely that significant. The second is a penalty that's usually worth keeping (you want bounds checking on arrays), and the third misses the point.
Sure the expert c++ developer could write faster code, but is that who you have? Are you going to take the time to do all that optimization work?
No, apr_pools.h was not custom written to make some programming language look better on a toy benchmark!
That, and having to handle vendorized dependencies.
Do you have a source for this?
We already have web server that do "logging, tracing, health check, graceful shutdown." I do not care about zero deps, because I only install them once and the deps are taken care of by the package manager.
In my opinion, the Go web server only makes sense as part of a Go application as a whole. But a standalone Go web server does not make much sense to me.
> "I think this is likely a useful exercise. That said, I'm not sure I see myself actually using this."
> "We already have web server..."
Yeah, it's subtle, but I think it comes off differently as it's more upfront that doing this may actually have had a use. And both the writer and the reader are involved in the communication: you yourself can only control so much.
Anyway, this is only speculation.
We should always try to strive to lower dependencies when it makes sense.
Maybe, but I think 'when it makes sense', might be 'rarely'. There a 2 ways to avoid dependencies: 1. lean on a batteries-included standard lib as this gist does or 2. write it yourself.
Problem with 1. is standard lib libraries aren't always great, see 'where modules go to die' [1], (examples: httplib/urllib in Python, or the string libraries in PHP). This can stifle innovation and alternatives, unless an alternative with a strong marketing push can arise ('requests' for Python). Sadly, often because the situation isn't 'that bad' (as in the case of PHP) people continue to use poor APIs.
Problem with 2. is you're probably getting an order-of-magnitude fewer brain cycles on code you wrote yourself -- unless you can spend the extra effort to open-source it, and get lucky with popularity/contributors, it's likely to be inferior than a well-maintained 3rd party alternative.
[1] http://www.leancrew.com/all-this/2012/04/where-modules-go-to...
I'd encourage developers, especially Nodejs devs, to look at their list of dependencies and ask the following two questions about each of them:
1. How long would it take me to replicate this functionality?
2. How often does this functionality need updating?
There is a threshold balanced between both of those questions where, once the numbers pass, it makes sense to bring in dependencies. But I truly believe the "instant gratification" primate part of our brains tends to overestimate the benefit of dependencies and underestimate the long term negatives of them.
Here's a common Nodejs example: Request. Request is used all over many projects. Did anyone who imports it even try to use http.request in the nodejs stdlib? Its actually pretty great. Now, you introduced a new dependency. You made your build process longer. You made your deploy artifact bigger. You've got to keep it up to date. You've got to make sure there aren't security breaches. You've got to learn a new API that, unlike the Nodejs stdlib, is just made by "some guy somewhere" and is horribly documented inside a Github README.
How long would it take me to replicate the functionality of request just using http.request? It depends what parts of request I'm using, but probably very little time. How often does this functionality change? Literally never. Literally never. HTTP/1.1 was finalized decades ago. Request, right now, has 48 open PRs, 560 open issues, was last "released" a couple months ago, and was fixing security issues which were definitely already fixed in stdlib.
But the primate part of your brain says "Eh fuck all that, I'll let future self deal with the negatives of a new dependency, what I want today is an API interface that's, like, 20% easier to use."
I only use the stldlib in Go, and a few packages (like google/uuid) that will become part of the stdlib at some point.
I know exactly what my program is doing, and why.
In Node, I would often hit 100+ dependencies before getting to the actual meat of the thing, and if there was a problem I had no idea where to look in the mess of other people's code. Given the number of PR's on the average node module, and the number of dependencies, I was guaranteed to be importing bugs every time I used an external module. Whether I hit one of those bugs and had to deal with it was a matter of luck. Dealing with bugs in someone else's library is a million times worse than writing the code myself.