Labstack/echo: High performance, minimalist Go web framework
github.com
github.com
Deviating from the standard allows you to tackle these ‘problems’. In the end I think there is room for multiple frameworks/libs for different styles and purposes.
Echo and Gin deviate from http.Handler because they want to be frameworks and stamp their framework-specific type signatures all over your codebase.
That doesn't feel in spirit with the use of context. I am not saying you are wrong just that it makes me realize I would not have even considered doing something like this.
Have you worked with a library that does this? Curious if this is this more common than I realize?
Echo and Gin have their own Context structs, except instead of http.Request wrapping their Context struct, their Context struct wraps http.Request (thereby rendering it incompatible with the stdlib). It's not a far stretch to have these frameworks retrieve their Context from the http.Request. Instead of
// echo Handler
func(c *echo.Context) {
}
they could do // standard Go handler
func(w http.ResponseWriter, r *http.Request) {
c := echo.GetContext(r)
}In many ways, Echo is a "better Gin".
I see Gin can expose the stdlib context:
router.GET("/", func(context *gin.Context) {context.Request.Context()})
> In many ways, Echo is a "better Gin".Interesting. I find it difficult to compare the plethora of web frameworks in Go. But coming from Python, I'm also familiar to this kind of situation...
I can see how having Echo's build-ins be a benefit if you have a pretty big applications with rich API and quite a few people working on it. But in case for microservices - it's just makes things needlessly complicated.
The reason why I chose Echo among all of the Go web "frameworks" was that it didn't use FastHTTP, which is used by many (most?). I however ran into a (simple) pattern of endpoints a long time ago that you could not be matched by FastHTTP and realized the speed improvements may not be worth it. There was also no http2 support back then. Too many people just look at micro-benchmarks for these frameworks.
One of the greatest things about the standard library HTTP handlers is that you have an io.Writer that you can do whatever you want with.
It looks like this library removes the flexibility of that and instead provides a worse API to the user.
I feel like they could still have a good module here if the performance gains are independent of the actual handler API.
I don’t want “frameworks”, I want composable modules that I can mix and match. Things should be small and simple.
> It looks like this library removes the flexibility of that and instead provides a worse API to the user.
You can get to the stdlib http.ResponseWriter and http.Request with Response() and Request() methods
I ended up having to teach the vendor of the tool about go mod.
But if you are publishing a “release” I personally think it is good to tidy that up. Even just to prevent misconceptions. No reason to preserve ancient versions and especially failed library experiments.
P.S: Logging is still a bit of mess in the Go ecosystem!
That said, Zap (by Uber) has proved itself and is a solid choice. We've used it in several projects at [company], handling very high loads.
I think the stance on logging by the core Go team is the right way to go about it. Just provide a basic logger, an interface, and let the projects determine how they want to route those logs and what kind of data should it include.
The log package in stdlib doesn’t let you specify levels, just a Printf unless Iam mistaken, and it is not an interface I believe.
They both deviate from standard interfaces (eg. https://pkg.go.dev/net/http#Handler) and do their own thing. This is fine, but unidiomatic.
The Go community steers towards 'one way of doing things', meaning that packages that don't reuse established interfaces tend to be less popular compared to the ones that do (gorilla, chi, or just std).
I would argue that 'one way of doing things' is really at a much lower level, not at the package or module level. That was tied to "one way to loop, one way to place curly braces" Extending this idea to modules is not actually in line with how the GO team and community works.
Ah, I wasn't aware! It was heavily used a few years ago.
> Extending this idea to modules is not actually in line with how the ... community works
This is not my experience (with the community).
Packages that heavily reuse common interfaces (combinations of io.Reader|Writer|Closer|Seeker, http.Handler, http.ResponseWriter etc) tend to be more popular and recommended than packages that invent their own interfaces.
That is, unless the recommendation is just 'stick to the std', which has been a knee-jerk reaction from the community (reddit, slack) for a lot of problems, especially concerning new comers.
- it ships a pretty extensive collection of middlewares that will get you to 80% faster
- the documentation[2] is really well written and accessible to new web developers: most "must have" features have a cookbook page, so you don't have to google for blog posts.
- it does indeed use a custom handler function signature, but in my opinion this one is better (returning errors instead of handling them locally in each handler). You can still use handlers and middlewares written for other frameworks (for example the great statigz[3] handler) through the `echo.WrapHandler` and `echo.WrapMiddleware` functions
[1] https://github.com/letsblockit/letsblockit
The one thing, authors could build as a differentiating factor is to provide openapi spec support out of the box. I have not seen many golang web frameworks provide first class support for building using openapi spec.
People are welcome to create whatever abstractions they want but I highly encourage new golang users to experiment without web frameworks using the standard library and minimalist libraries like gorilla/mux, sqlx, and squirrel, to compose your web applications with much less of a headache.