Working with Go Web Frameworks — Gin and Echo

Recently I spent a lot of time working with both Gin and Echo. Primarily I wrote an open source restful starter kit named Gorsk (GitHub/Blog post). Besides Gorsk, I’m working on two web apps utilizing Gin/Echo. Even though the reasons for (not) using Golang’s ‘Web frameworks’ are mentioned quite often, I have built my own opinion on these.

I believe most newcomers to Go, coming from languages such as Java, Python or Ruby, tend to search for Web Frameworks. They have experience working with Rails, Django or similar frameworks and they expect something similar in Go.

Go doesn’t feature anything similar to those. We can debate whether this is a good or bad thing, but that’s how it is currently.

Go does feature ‘smaller’ frameworks, most notably Buffalo. Next to Buffalo, there are other ‘backend’ frameworks such as Gin, Echo, Chi and many more (but not Iris please).

In those, you’ll find router handling (usually better feature-wise and or performance-wise compared to stdlib’s), server implementation, request/response handling/ marshaling, error handling. And that’s about it.

When I started writing Gorsk I looked into all those available frameworks and decided to use Gin, as it seemed mature enough. Fast-forward three months and my opinion vastly changed. Not on Gin only, but on all of those Go’s web frameworks.

Golang web frameworks benchmark (source)

Although Echo, Gin, and others are not to be considered web-frameworks à la Rails or Django, they offer a vast set of helpful methods to help you get started with building a backend in Go.

  • Routers with far better performance and route matching capabilities compared to net/http’s with things like router groups and helper functions
  • Extensible middleware framework, define middleware at root, group or route level
  • Request serialisation and validation
  • Handy functions to send a variety of HTTP responses
  • Tons of examples

And probably much more. These things help a lot while developing a restful backend, especially having a fine documentation website like Echo does. And the maintainer is very active on Gitter / GitHub issues.

Given a choice between Echo and Gin, I’d definitely go with Echo nowadays for several reasons. Most notably:

  • Active development and support
  • Documentation
  • Nicer handler func signature (returning an error)
  • A router without absurd pattern matching issues.
  • Less opinionated on certain things like validation (e.g. bring your own validator)
  • Centralized HTTP error handling

Although, not everything is positive for these frameworks. An example — Gin’s router pattern matching is awful. You can’t have GET /users/token and GET /users/email routes. There were proposals to replace it with another router, but the problem still remains. The workaround for this is quite ugly. Also, the project is very inactive now, with barely any commits, responds to Issues/PRs.

With Echo, what drew complain is that echo.Context does not implement context.Context (where Gin’s context does), leading to some unnecessary allocations if you need stdlib’s context. I’ve read a couple of complaints on Reddit on Echo’s provided middleware (notably Gzip) having some issues, but I haven’t encountered them yet.

But all of these can be on these is that they are too opinionated on how you should get things done. Using ‘Go’s vocabulary’, they are not idiomatic.

The handler func signature is changed from stdlib’s func(w http.ResponseWriter, r *http.Request) to something like func(c *gin.Context). You might consider this either good or bad, but migrating from one to another becomes painful and it might confuse newcomers.

If you experience a problem/bug with the library, eg. Gin, which has a much higher probability compared to having a bug in net/http, you’ll face plenty of spaghetti code while debugging. There might be a bug with some middleware, routing, context passing etc. which you may only experience in high-load environments. I’ve also read on Reddit (might find the actual comment and post it here) where a user complained that using Echo in production lead to 100% memory usage every hour or so, for no reason, and then simply dropping. Good luck finding out the main cause if you experience something similar. Standard lib has way fewer failure points and is easier to debug.

Most people jump on popular ‘frameworks’ and libraries with most stars once they start working with Go. Since they’re coming from languages where such frameworks are widely adopted, they expect same with Go.

I highly advise everyone, before jumping ships on Go’s ‘frameworks’, spend some quality time with the standard library. Learn its pros and cons. I do not advocate against Echo and Gin. I use Echo in several (small) projects that are in production. Works fine for now.

Lately, I’ve been playing with Twirp — it seems quite productive so far. I might post an article about Twirp in following weeks.

Also, I have plans to rewrite Gorsk yet again, this time in Chi. Chi seems quite close to stdlib that I may actually stick with it for a while. Time will tell.