4 Things to Consider When Choosing a Go API Framework
Tags: go, beginners, webdev, programming
Published: 2021-11-16 22:35:40

This post originally appeared on [my personal blog](https://markphelps.me/).

So you've decided to write an API service in Go... great!

One of the first things many newcomers to the language ask is, "Which framework should I use?".

Those coming from languages such as Ruby or Python may be familiar with a single web framework that is used by the majority of developers such as Rails, Django, or Flask. Go is a bit different in that there isn't really a single framework that is the most popular in the community. While there are several frameworks available, many of which I will discuss in this post, the Go community doesn't seem to agree on which, _if any_, is the 'go to' framework when building an API service.

While I won't be comparing or recommending any specific frameworks in this post, I will try to guide you by presenting four key things you should consider when choosing a framework for your next API project in Go.

## 1. Do You _Really_ Need a Framework

One of the first things you should ask yourself when trying to figure out which framework you should use when building an API backend service in Go is, **do you need a framework at all?**

The Go standard library is pretty awesome and since Go was released [not that long ago](https://go.dev/blog/12years), it comes with many of the pieces you need to build a world-class API right out of the box! I've personally helped architect and build a service in Go that handles millions of requests per day using nothing more than the Go standard library + a router/mux.

Two of the most popular routers are:

- [gorilla/mux](https://github.com/gorilla/mux)
- [chi](https://github.com/go-chi/chi)

Both of these libraries provide fast request routing based on things such as the URL host, path, headers, HTTP methods, and query values while allowing you to define your own 'custom' matchers.

These routers provide a nicer experience over the built-in [http.ServeMux](https://pkg.go.dev/net/http#ServeMux) as they allow for routing your requests to different handlers without the need for a complicated block of `if` or `switch` statements such as:

```go
func (b *bookServer) bookHandler(w http.ResponseWriter, req *http.Request) {
 // how you'd have to implement method based routing if using only the stdlib
 if req.URL.Path == "/books/" {
   if req.Method == http.MethodPost {
     b.createBook(w, req)
   } else if req.Method == http.MethodGet {
     b.getAllBooks(w, req)
   } else if req.Method == http.MethodDelete {
     b.deleteAllBooks(w, req)
   } else {
     http.Error(w, fmt.Sprintf("expect method GET, DELETE or POST at /books/, got %v", req.Method), http.StatusMethodNotAllowed)
     return
   }
 }
}
```

Eli Bendersky has an [excellent series](https://eli.thegreenplace.net/2021/rest-servers-in-go-part-1-standard-library/) where they walk you through building a REST API in Go by first starting with the standard library and then introducing a router such as [gorilla](https://github.com/gorilla/mux) or [chi](https://github.com/go-chi/chi) and finally switching over to using a complete web framework. This series shows some of the downsides of sticking with the standard library entirely and how extra libraries such as the two router packages above can be extremely helpful.

While both of these routers come with middleware for handling things such as Basic Auth, CORS negotiation, request logging, and others while also allowing you to easily integrate your own, they still are not _frameworks_.

If your API is simple enough, or especially if you or your team is just getting started in Go, I would recommend starting with using only the standard library + a router/mux and seeing how far you can get before making the jump to a full framework. This approach will allow you to learn the basics and not be bogged down by the nuances of more complicated frameworks.

## 2. How Opinionated Are You

If you've decided that you still would like to use a web framework for your new service, you have several popular choices including:

- [echo](https://github.com/labstack/echo)
- [gin](https://github.com/gin-gonic)
- [buffalo](https://github.com/gobuffalo/buffalo)

These projects can be described as complete web frameworks as they handle much more than just routing and middleware. They provide built-in and pre-configured functionality for other aspects of your service such as:

- logging
- templating
- i18n
- data validation
- asset serving
- database access and ORM
- etc

This can be extremely helpful if you just want to get going and start writing the business logic of your application without having to worry about some of these implementation details however it does come with a price: you're mostly stuck with the framework's choices. Don't like the way that [echo](https://github.com/labstack/echo) formats logs? Tough. Want to use a different router than the one chosen by [buffalo](https://github.com/gobuffalo/buffalo)? Good Luck.

I'm not saying it's impossible to swap dependencies when using these frameworks, but it will probably be difficult as pretty much the entire point of a framework is to make these choices for you. If you or your team is OK with the dependencies chosen by a framework then it may be a good fit for your use case and in fact, be a productivity booster. However, if you are the type of person or team that likes to choose your dependencies and tweak them or swap them out from time to time, you may quickly find that a framework is not the best choice for you.

## 3. Project Pulse

The number of open issues for a project on GitHub as well as how responsive the project maintainers are to those issues and pull requests is also an important 'soft' metric to keep in mind. While having a large number of open issues doesn't necessarily mean that the project is lacking, it could mean that some feature or inner-working is unclear and not documented as well as it could be.

**Note:** This isn't always the case as it could also mean that the project is gaining steam and people are excited about contributing new features. Click through the issues and pull requests to get a sense of what's happening with the project.

If however, the project maintainers don't seem to have a good rapport with the community, or they don't respond very often to issues or discussions, this could mean that you may find yourself waiting for an answer or bugfix to be merged should you choose that particular framework. GitHub's somewhat overlooked [pulse view](https://github.com/gin-gonic/gin/pulse/monthly) can help show how active a project is and how often issues are opened and closed.

Most popular frameworks will also have a dedicated Gitter, Discord, or Slack, so it may also be worth popping in there to see how helpful the community is to newcomers.

## 4. The Future

Finally, it may be worth comparing the popularity of your framework of choice against others as waining popularity may mean the project could become abandoned or stagnant as the community moves to another solution. While the number of stars on GitHub is an OK indicator of a project's popularity, this doesn't tell you how the tide may be changing as much as a Google Trends search would. Here's an example of a Google Trends search comparing the interest of [golang echo vs golang buffalo](https://trends.google.com/trends/explore?geo=US&q=golang%20echo,golang%20buffalo) in the US over the past year.

![Golang Echo vs Golang Buffalo search trends](https://s3.amazonaws.com/markphelps.me/2021/go-framework-trends.png)

Doing a search on [r/golang](https://www.reddit.com/r/golang) for your framework of choice may also give you some different opinions from others in the community on the project's usefulness and potential future.

While this isn't full-proof, and no one knows the future, this tactic along with looking at the project's pulse as described above should give you a relatively good idea if the framework is starting to die out or still going strong. This is especially important if you are choosing a framework on behalf of your team for a work project, as many of us have been in the unfortunate situation of having to maintain an application built on top of a framework that no longer receives any bugfixes or security updates.

It's also worth checking out the framework's documentation to see if it is up to date and if there are any recently published tutorials using the same framework and major version. If no one's writing about it online it may be a sign that it's not as relevant as it used to be.

This is one area where choosing the standard library over a third-party framework has an advantage, as the standard library is never going away and doesn't change much.

## Bonus: The One Thing That Doesn’t Matter (That Much)

Wrapping up, I think one 'feature' that framework authors [overly](https://github.com/gin-gonic/gin#benchmarks) [push](https://github.com/labstack/echo#benchmarks) is performance. While performance is important, I don't think that choosing a web framework mainly because it is the most 'performant' makes a lot of sense, especially in Go. Go is already extremely fast and your framework code will most likely not prove to be your application's bottleneck. Your database, network, or simply your own application code will most often be the source of your service's performance woes long before you need to start profiling and optimizing your framework.

While it may _feel_ nice knowing that the framework you chose is `10ms` faster than another, your users aren't going to ever notice a difference.

## Conclusion

Simply put, choose the framework (or none) that is right for you or your team as there is no 'right' answer for everyone. If you have decided that you really want to use a framework, I'd recommend picking at least two and implement the same simple CRUD API in both to see which you like best.

Do you agree or disagree with the points in this post? What frameworks have you and your team tried? Which one is your favorite and why? Let me know on [Twitter](https://twitter.com/mark_a_phelps)!