Why You No Framework?
If you’re a new Go developer preparing to build an HTTP API there is a good chance you’re about to ask some form of the question: Which framework should I use to build my API?
Thank you to all attendees of the Denver Gophers Meetup for inspiring the topics covered in this post during conversation after a talk I gave on chaining http middleware.
Why do you react this way? Why You No Framework? This article will explore the unique position of Go in time and attempt to provide insight into the standard library first approach. I’ll focus on comparisons to Ruby and Python as I’m familiar with the framework ecosystems of those two languages . However the logic should apply to most pre-Go language common for building HTTP API’s.
Why Do Frameworks Exist?
[frameworks are needed] to hide the boilerplate and infrastructural code related to handling HTTP requests and responses. Just how much is hidden depends on the framework. — Jeff Knupp
This makes sense, and is a solid software practice. Frameworks abstract the common (boilerplate) that we use over and over again when building API’s. Some take that to the extreme (Django, Rails, …) and some abstract the minimal set of features you need (Flask, Sinatra). So, if we accept that abstracting common functionality is a good thing why would I tell you not to reach for a framework when starting to build an API in Go? This question can be explained by the time in which Go was developed.
A Series-Of-Tubes 2.0
A major milestone for the internet, Web 2.0 began it’s rise toward popularity sometime around 2004. This represented a shift from static web pages to dynamic, user-generated, social content. This also represented a shift in software development to a strong focus on building publicly available RESTful HTTP API’s. What does all this have to do with using a web framework? Stick with me…
The Python programming language was introduced in February 1991, Ruby in 1995. The internet (in it’s infancy) was introduced in August 1991. This means that the core of Python & Ruby were built in a time where the internet, and certainly modern HTTP API’s were not a problem software engineers were solving. As the internet progressed and the need to build API’s presented itself it was up to the communities of those languages to build frameworks on top of the standard libraries to solve new problems the languages themselves were never designed to solve. And build frameworks they did! Neat, but what about Go?
Here We Go!
Go was introduced in 2009, well into the modern era of API development. The simple fact is the Go language WAS designed to solve the problem of building HTTP API’s. Instead of the community needing to build framework’s (though many still are) we have a standard library package (net/http) that already does what we stated frameworks are for (abstracting boilerplate). If you’ve got a keen memory you might remember the second part of Jeff Knupp’s quote:
Just how much is hidden depends on the framework.
So where does net/http fall in this range of abstraction. In my opinion it falls on the minimal end (similar to the level of Flask and Sinatra). It provides abstraction of the very basic thing’s you’ll need to construct an API. This leaves some developers (fans of Django or Rails) with a desire for more abstraction. Does this mean that there is room for frameworks in the Go ecosystem? Maybe. However, I’d suggest you consider a take-only-what-you-need approach. By this I mean select a single-purpose library to solve the problems you don’t find solutions for in the standard library.
Do you need structured logging? Take a look at Logrus or Zap. How about a database layer? You might want to reach for database/sql, sqlx, or Gorm. Is the standard mux/router not up to par? Give httprouter or gorilla/mux a try. There are plenty of single-purpose, pluggable solutions to individual problems you may need to solve. Many are compatible with the standard library (always a good thing). Taking this approach you can often avoid the overhead of large frameworks providing additional features/abstractions you don’t need.
So, No Frameworks Then?
Not quite. There are some really interesting projects that provide more than just an abstraction of code and can still be considered frameworks. The best example of this is goa. The major difference between a framework like Django or Rails (Echo, Gin, Beego, … in the Go world) and goa is that instead of just abstracting everything possible:
goa takes a different approach to building these applications: instead of focusing solely on helping with implementation, goa makes it possible to describe the design of an API in an holistic way. goa then uses that description to provide specialized helper code to the implementation and to generate documentation, API clients, tests, even custom artifacts.
My personal opinion is that there is always room for this type of framework. Something that provides more than just an abstraction, a different approach to the problem. In this case writing what essentially is the specification of your API and letting goa generate the actual implementation (and lot’s of other goodies).
I hope that this article has shed some light on why Go takes a standard library first approach to building HTTP API’s. I also hope that this article helps new gophers understand the answer they receive when asking the question: Which framework should I use to build my API? I myself asked the question: Which framework should I use to build my API? The answer then, and my answer now. Give net/http a shot.