
A Comparison of Go Web Frameworks - ImJasonH
http://corner.squareup.com/2014/05/evaluating-go-frameworks.html
======
abtinf
Posted this on the blog as well, but some here might find it useful.

Instead of duplicating code to implement common/middleware functionality, I
like to just pass around functions. I usually just have one
makeStandardHandler type function that covers most cases. For the special
cases, I can easily combine middleware in any order for the desired result.

    
    
      // Execution timing middleware
      func makeTimingHandler(fn func(http.ResponseWriter, *http.Request)) http.HandlerFunc {
      	return func(w http.ResponseWriter, r *http.Request) {
      		requestStartTime := time.Now()
      		fn(w, r)
      		totalRequestTime := time.Now().Sub(requestStartTime)
      		log.Printf("URL: %s TIME: %s", r.URL.Path, totalRequestTime.String())
      	}
      }
      
      // Serve up one file
      func makeSingleFileHandler(file string) http.HandlerFunc {
      	return func(w http.ResponseWriter, r *http.Request) {
      		http.ServeFile(w, r, file)
      	}
      }
      
      func main() {
      	...
      	http.HandleFunc("/robots.txt", makeTimingHandler(makeSingleFileHandler("./s/robots.txt")))
      	http.HandleFunc("/", makeTimingHandler(indexHandler))
      	...
      }

~~~
elithrar
> Instead of duplicating code to implement common/middleware functionality, I
> like to just pass around functions.

The problem there is that it doesn't allow you to either:

• Apply the middleware to routers or sub-routers;

• You end up with http.HandleFunc("/",
loggingMiddleware(recoveryMiddleware(sessionMiddleware(myHandler)))) - which
is no fun, repetitive and prone to errors

• There's no request context - your handlers have no way to communicate
between themselves (i.e. passing a CSRF token from middleware to the handler
rendering the template or writing to the response header)

It does work for basic applications, but it just doesn't scale beyond more
than a (small) handful of routes. I wrote a little function[1] that helps with
avoiding the gratuitous function nesting, but you'll need to BYO request
context in many cases. This often ends up being map[string]interface{} (so you
may want getters/setters to wrap types coming in and out), as the alternative
is to rely on structs + methods (ala
[https://github.com/gocraft/web](https://github.com/gocraft/web)) which can be
a little unwieldy. Horses for courses, as they say!

[1]:
[https://gist.github.com/elithrar/21cb76b8e29398722532](https://gist.github.com/elithrar/21cb76b8e29398722532)

------
elithrar
Goji ([https://goji.io/](https://goji.io/)) is a really nice middle ground
between bare net/http (and writing your own boilerplate over and over) without
any dependency injection, fairly sane middleware chaining and no global
request context map (so no need for locks!).

I've been playing around a fair bit with Goji and gocraft/web over the last
week and enjoy both their approaches, and may end up porting over a gorilla/*
+ net/http project to get some sanity out of my middleware and request
context.

------
Yuioup
It's a real shame that TL;DR has now become the norm.

I can't find the link right now but there was an article somewhere stating
that the TL;DR is a redundant construct because if you want to summarize your
article you should do it at the top, in the first paragraph.

That first paragraph is called an "Introduction".

Funny enough the author of the blog post wrote a good introduction to his
article, but chose to tack a TL;DR to it.

~~~
andreif
Introduction is usually longer and is often used to introduce the reader to
the subject. You probably mean
[http://en.wikipedia.org/wiki/Abstract_(summary)](http://en.wikipedia.org/wiki/Abstract_\(summary\))

------
notduncansmith
Just to throw my 2 cents in, I've had a blast using Martini for the past few
weeks working on Hacker News Anchor[0]. It's a pretty minimal product, true,
but using Martini I barely noticed the framework. I may be biased since I tend
to heavily prefer Sinatra-style frameworks, but Martini didn't disappoint.

[0] [http://hidden-bastion-5609.herokuapp.com/](http://hidden-
bastion-5609.herokuapp.com/)

~~~
jacquesm
Martini is now succeeded by negroni, see:
[http://codegangsta.io/blog/2014/05/19/my-thoughts-on-
martini...](http://codegangsta.io/blog/2014/05/19/my-thoughts-on-martini/)

(negroni is another coctail...).

~~~
sagichmal

        > Martini is now succeeded by negroni.
    

From the link,

    
    
        > Martini is not going away, and I’m not going to stop 
        > supporting Martini.

------
ericflo
Surprised not to see Tigertonic in this, which has a large following on GitHub
and puts more emphasis on monitoring and operations:
[https://github.com/rcrowley/go-tigertonic](https://github.com/rcrowley/go-
tigertonic)

~~~
elithrar
Tigertonic has a really nice API, but is also fairly JSON orientated. I think
when many people say "web frameworks" they implicitly mean "serving at least
some HTML", even if we all know the web != just HTML.

~~~
ericflo
That's a fair point.

------
oakaz
If what you need is something minimal, then why not to use a JSON API server
and have your front-end app use your API.

I compose APIs from Go and NodeJS servers and get really good productivity &
performance benefits. And this is what I use;
[http://github.com/azer/atlas](http://github.com/azer/atlas)

~~~
phea
I'd disagree having a backend written in Go and a front-end written in another
language is being minimal. Plus I think the majority of people attracted to Go
are fundamentally opposed to Javascript.

~~~
marcus_holmes
I don't think there's any other choice. You can only write javascript in the
browser (anyone who writes in Go _has_ to be fundamentally opposed to hacks
like coffeescript).

I write Go on the server to serve pages, and write rich front ends using
simple javascript and jQuery. Being able to do nice quick page fetches means I
don't get into massive complexity on the front end with a bloated single-page
app, and not trying to deal with front-end complexity on the server means my
server routes stay nice and simple.

I use Gocraft/web on the server because it's a useful library not an
opinionated framework, and IMHO the most Go-idiomatic of the options (I tried
them all and it was a toss-up between Gorilla and Gocraft/web, which won
because of the really simple, useful context and middleware paradigm).

Creating API endpoints and page routes is simple and easy, and then writing
the javascript to call endpoints when needed is simple (once I'd learned to
stop jQuery from appending my data to the url and put it in the request
body!).

My only gripe about the mix is that GoConvey doesn't integrate with Jasmine so
I have to run two test suites.

~~~
icebraining
_anyone who writes in Go has to be fundamentally opposed to hacks like
coffeescript_

Why? In fact, there's someone writing a Golang → Haxe transpiler, which is no
less of a hack than CoffeeScript:
[http://tardisgo.github.io/](http://tardisgo.github.io/)

------
thinkpad20
Minor comment, but the faint gray text is a bit hard to read.

------
optymizer
I'm currently working on releasing a fast Go framework. Expect a new player to
join the framework game.

------
kyrra
For the routing side of things, HttpRouter[0] seems like a nice alternative
when performance matters to you. But as the author of this post referred to,
sticking with the basics is a nice way to go. The nice thing about a lot of
these frameworks, is that you can use bits and pieces of them if you'd like,
you aren't required to use all the functionality.

[0]
[https://github.com/julienschmidt/httprouter](https://github.com/julienschmidt/httprouter)

------
ilaksh
So the decision is, even though there are many good Go frameworks for web
development (they forgot some, like beego), to invent their own micro-
framework? I think basically they just re-invented a small aspect of some of
the frameworks they dismissed.

I have made similar decisions before, and it is more fun and certainly gives a
sense of freedom and less to learn, but I think that is generally an incorrect
decision and in this case it is particularly obvious. There are many existing
Go web frameworks, and I am sure that some existing Go web frameworks are good
enough for Square.

This sort of thing is why I prefer to work alone. Because those types of
incorrect decisions are very common. There is always more than one way to do
something. It is just surprising to me how often engineers carefully select
the ways that are inferior (more work, and/or less sophisticated). Of course,
as I said, sometimes I make wrong decisions, but in those cases I can always
change my mind. An organization or another individual is harder to change
though, and bad design decisions can become solidified.

------
burke
[https://code.google.com/p/gorest/](https://code.google.com/p/gorest/) is
another one worth considering if the overhead of routing with net/http feels
too much.

------
zimbatm
Got a couple of net/http compatible extensions here as well:
[https://github.com/zimbatm/httputil2](https://github.com/zimbatm/httputil2)

------
mixologic
" too much dependency injection and other magic" "No dependency injection. No
magic."

What do they have against dependency injection? Why do they think its 'magic'
?

~~~
mrweasel
I don't know why the authors of the article dislike dependency injection, but
I think it comes down to how you view your code. Dependency injection sort of
hides what goes on in your code and makes it hard to follow.

Developers who are used Rails, Django, Laravel and other large frameworks
might not really care, and they might not need to. You develop for and with
the framework you picked an understand and accept that stuff works a certain
way, because that's what the framework does. If however you're a Go developer
and want to do web development Gorilla will seem like a better approach than
Martini og Revel, because it's just add the bits you're missing. Picking a
larger framework and you get locked in doing stuff their way, and the
dependency injection and "magic" makes it hard or impossible to escape the
framework, should you want to.

For me, I like to be able to look a just my own code and reason about what it
does, without ending in "here I pass a bunch of stuff of the framework and
hope it does the right thing". Normally I know what I want and if the
framework has these magical bits they more often than not get in the way...
I'm looking at you stupid Django Rest Framework.

