Technology

A Survey of 5 Go Web Frameworks

24 Nov 2014 10:46am, by

After a few years building socket servers in Go, I suddenly had the need to build out some HTTP based REST APIs for Javascript and Objective-C clients. Having a background in Rails I have pretty high expectations for a general purpose MVC framework. However frameworks like Sinatra in Ruby strike a nice balance of simplicity for simple REST End points. I chose to continue with Go for this, because of the performance and static typing, I think will win out long term on projects that don’t need to do a lot of templates and forms in traditional web app style development.

Beego

Beego looks to be a full featured MVC framework, maybe on the same level as Rails. It doesn’t make any attempts at being small. It has its own logging library, ORM and Web frameworks.

Community:

The Beego community is quite large. However it appears most of the companies using it are Chinese, so there is definitely a language barrier to this community. It can probably scale to a lot of traffic as massively large Chinese sites use the framework.

Best Feature:

Since this is a full fledged MVC framework, you don’t have to scour the net for tons of libraries. A lot of questions go out the window right away such as what logging framework to use and how to structure the application. These are the kinds of features that save a lot of time at the start of a new project.

Martini

Martini, inspired by Sinatra, has the feel of a very lightweight framework. It handles basic things like routing, exception handling, and common methods for doing middleware. Initially there was some backlash in the Go community as it has a lot of reflection techniques to cleanup the API structure from routing. It can do cool things like dynamically inject different sets of data into handlers based on types (see best feature for an example). This ‘magic’ which is common in Ruby frameworks, has gotten a lot of heat in the Go community. So much so that the author is working on a simpler framework called Negroni. However, in my opinion, it does not provide as much value as  Martini does.

Community:

Albeit a smallish community, it still seems very active and there are about 20 or so active plugins , also I have one for integrating into GetSentry source. Given that the mantra of the framework is to be small, it makes sense there isn’t that many things you need add ons for.

Best Feature:

Since the framework uses reflection it can dynamically insert data into the handler functions, depending on your needs see this example below. You can even dynamically add new services.

m.Get("/", func(res http.ResponseWriter, req *http.Request) { // res and req are injected by Martini
  res.WriteHeader(200) // HTTP 200
})
m.Get("/", func() {
  // show something
})
m.Get("/", func(c *Context, r render.Render) {
  // show something
})

Gorilla

Probably the largest and longest running Gi web framework, Gorilla is a modular framework that can have as much or as little as possible for the user. For example, in one project we just took out the Sessions package and reused it for Auth. I think Gorilla is nice cause a lot of the components are reusable with straight net/http library.

Community:

Gorilla probably has the largest English speaking community of all the frameworks. It shows, which the shear volume of blog posts and middleware available on GitHub.

Best Feature:

I think there is a lot of hype these days around using web sockets to dynamically update applications in frameworks like Meteor.js . Gorilla has web sockets out of the box, so you can hook up the exact same code to REST endpoints as your web sockets without using a third party service like Pusher.

GoCraft

I really wanted to touch on this framework at least briefly. I think one of the largest issues with net/http is there is no way to pass context to your handler chain. So you can’t easily share data or transactions between your middleware and handlers. This framework aims to be super minimal and solve just this problem. Let me show you a couple of quick examples

Lets take the typical example, where some piece of middle authorizes a user and then puts a user object into the session.

router := web.New(YourContext{})
router.Middleware((*YourContext).UserAuthRequired)
router.Put("/users/:id", (*YourContext).UsersUpdate)

func (c *YourContext) UserAuthRequired(rw web.ResponseWriter, r *web.Request, next web.NextMiddlewareFunc) {
    //Auth the user and put the data into the context
    user := userFromSession(r)  // Pretend like this is defined. It reads a session cookie and returns a *User or nil.
    if user != nil {
        c.User = user
        next(rw, r)
    } 
}

func (c *YourContext) Root(rw web.ResponseWriter, req *web.Request) {
    if c.User != nil {
        fmt.Fprint(rw, "Hello,", c.User.Name)
    } else {
        fmt.Fprint(rw, "Hello, anonymous person")
    }
}

Net/HTTP

If you read the Go mailing lists, you might be told this is the only framework you ever need. In some ways its true. We built an entire XMPP server with just net/http, and works well. However complex web apps tend to need middleware. There are some interesting projects like interpose which allow you to mix and match middleware from other GO web frameworks with standard net/http.

Community

The community is obviously quite large as the user can reuse bits from a lot of other projects. However it has a very limited interface, and it doesn’t really define any standard way of extending middleware. The routing its quite weak out of the box so you typically use a framework with it.

Conclusion

We tried a couple of these frameworks to get a feel for it. We used Martini for our REST API. While we liked it, I think in the future I’m going to try using GoCraft instead as it is even more lightweight but solves the same context problems that Martini has. Perhaps we will adapt some of the Martini middleware as an experiment. Originally we tried using Gorilla for our admin system which I think this ended up being a big mistake. It really lacked how opinionated RAILS is, and a lot of little features for making really basic cookie cutter web apps. For straight up tradition form based CRUD apps, I think we are going to lean heavily towards Beego in the future, as it really feels like a full MVC feature set.

Feature image via Flickr Creative Commons

Matthew is a hacker, who splits his time between New York and Bangkok. He has written large scale XMPP servers for Thomson Reuters, ported Bloomberg.com to Ruby on Rails, and even worked in e-commerce for Gucci. In between his many contracts he runs a new startup called Langfight. He runs the Bangkok GO Lang Meetup, and publishes a blog about the funnier side of outsourcing called DistributedAgile. A free ebook on outsourcing is available on the blog. You can follow him on twitter at @kanwisher


A digest of the week’s most important stories & analyses.

View / Add Comments