7 ms·
Goji: a web microframework for Go
- leccine 12y agoSorry for my ignorance, how is this different, better than Martini? What is the main goal of creating a new framework (instead of getting the features you are missing implemented in the currently existing ones)?
- dayjah 12y agoOne of the huge benefits of contributing to existing projects is to fill in the missing holes. Off the bat I think goji is likely to be yet another web framework that someone picks up and builds insecure services with. Perhaps the time spent improving Martini would have been better than this?
- Jake232 12y agoFrom the Github page: Third, Goji is not magic. One of my favorite existing frameworks is Martini, but I rejected it in favor of building Goji because I thought it was too magical. Goji's web package does not use reflection at all, which is not in itself a sign of API quality, but to me at least seems to suggest it.
- codezero 12y agoWhat, specifically, about Goji do you see as enabling insecure services in a way that other frameworks protect against?
- dayjah 12y agoMy comment was a little off hand and out of keeping with our standard, I apologize for that. Let me try to better explain myself: There is a form of survival of the fittest taking place; new languages need frameworks for people to operate within. Those frameworks spring up, some work many some don't. You consolidate some into one, and then you build that out. It has won. Within it you have aspects that you want to change, so you contribute an alternative, to make those succeed you have to build clean interfaces. Once you reach this point you have a real framework: i.e. something opinionated about the relationship between varied modules. Rails is, imho, the best example of this - it has had millions of hours of code contributed to it by the OSS world. It has reached maturity to the point where people wish to make it behave differently. They can do this because of that maturity. When I see things like Goji, my frustrations are not at goji (again, I poorly expressed that in my initial statement - sorry) but rather at the fact that the initial ramp up period as described above is so inefficient. If you consolidate into one sooner then you're in a really good spot. From my POV golang already has a great micro-framework for web services - so why not invest the time in making that better? For example the graceful http server termination aspect (where goji shuts the listen socket down but services the remaining connections), why not contribute that? Why contribute routing? RE: security. Recently I came across a piece that delved into the depths of why websites are insecure. The author made the compelling case that a great number of reasons for this is that most engineers do not understand web security, and in some ways that is down to the spread in frameworks - some handle security as a first class concern, others do not. The ones that do not are "easier to use", and so proliferate.
- dljsjr 12y agoThe author discusses their reasoning and even mentions Martini specifically on the GitHub project page.
- zenazn 12y agoTo be perfectly honest, I'm not sure it is better (I was hoping you would help me decide that!), and I wrote it mostly because every aspiring programmer writes a web framework at some point, and it was time I wrote mine (it was a lot of fun :) ). But I think there's a good chance it is better. First, I think one important difference is that Goji isn't full of magical reflection. If Go had support for method overloading, its entire interface is type-safe. In contrast, Martini does a lot of magical object injection, and it's not clear until runtime if your routes will even work, or what they'll even do, or where exactly the memory for them is coming from. Second, I much prefer Goji's way of defining middleware. To me, middleware is like an onion (just like ogres!): each layer is a wrapper around the previous one. The way you write middleware in net/http is by wrapping the old http.Handler with a new one, and that's how I wanted Goji's middleware to work too. There's no magic "context.Next()", there's no magic dependency injection overrides, it's just http.Handlers all the way down. Anyways, I'd like to know if you think I'm right: again, I'm really not sure this is actually better than Martini (or $YOUR_FAVORITE_FRAMEWORK), but I think it comes from a slightly different set of principles, and ones that I think are worth considering.
- leccine 12y agoThank you for the detailed explanation. I think using these slim web frameworks makes it easy to refactor your code or swap out the framework. I agree with some of the points you raised, but at this stage Martini has some very crucial features like model validations and sessions etc. I am pretty sure Goji gets those as time passes. Great work!
- pspeter3 12y agoThis is a great explanation. Thank you!
- beefsack 12y agoThe fact that you're trying to stick with strong typing as much as possible is very appealing to me, and now I'm convinced to try to port my new project from Martini to Goji. I think this is a good point to differentiate yourself on, and perhaps it should be included in your elevator pitch.
- 12y ago
- rabino 12y agofwiw, I prefer Revel better than Martini.
- elithrar 12y ago> Sorry for my ignorance, how is this different, better than Martini? What is the main goal of creating a new framework (instead of getting the features you are missing implemented in the currently existing ones)? I truly do not understand this reasoning. Why build anything new at all if you can "improve" on something existing? (the answers range from "because the existing doesn't facilitate the changes I would like to make" through to "learning experience", and everything in-between). It is (thankfully) the opposite of this thinking that has given us the myriad of popular and useful web frameworks in other languages (Flask, web.py, Bottle, Sinatra, et. al) that all aim to solve different problems and/or offer differing levels of complexity/kitchen sink.
- ddoolin 12y agoA bit off-topic, but I love the site colors. I'd love that text theme for Atom if it's available?
- GuiA 12y agoOrange (keywords): #fd971f Red (strings): #f24840 Green (variables): #96c22e White (text): #ffffff Grey (background): #222222
- zenazn 12y agoThis was not the feedback I was expecting, but thank you :) It was based on my terminal color scheme (named "Solarized Darcula"—not sure where I found it) and the way vim happens to color my Go code.
- tptacek 12y agoThis is going to sound a little dismissive, but I don't mean it to be: I'm not sure I understand the value that these frameworks offer beyond the HTTP server interface Golang supports out of the box, plus a URL router like "pat" (or whatever the cool kids are using now other than "pat"). I see the clean middleware abstraction, but I find the idiomatic closure-based implementation of middleware adds only a couple extra lines of code, and in return I get total flexibility. What's this doing that I'm not seeing? I'm sure there's something; I'm writing this comment out of ignorance.
- nkozyra 12y agoI agree, I don't see it here, but there are some that have a lot of decent addons, Gorilla being the big one among them. But yes, short of robust routing, Go handles the micro framework fairly well out of the box.
- zenazn 12y agoActually, Goji grew out of a single deficiency in "pat": the fact that it does not have a standard way of defining request context. The big use case here is how you'd write a middleware that did authentication (using API keys, session cookies, ???) and emitted a username for other middleware to consume. With net/http, you end up with a lot of coupling: your end handler needs to know about every layer of middleware above it, and you start losing a lot of the benefit of having middleware in the first place. With an explicit middleware stack and a universal interface for middleware contexts, this is easy: everyone can code to the same single context object, and instead of standardizing on weird bound variables (or a global locked map a la gorilla), you just need to standardize on a single string key and a type. I think my ideal world would involve Go providing a map[string]interface{} as part of the http.Request struct in order to implement this behavior, but until we get that, I think Goji's web.C ("the context object") is the next best thing. There's one other thing pat hacks around: the issue of how to pass bound URL variables to the resulting handler. At first I was a little grossed out at how pat did it, but I've sort of come to terms with it. I still think Goji's way is better, but I don't think it's the reason I wrote (or a reason to use) Goji.
- 12y ago
- kohanz 12y agoPerhaps this is not the best place for this question, but as a frequent HN reader, I'm constantly told that Go is great to develop in and very performant. However, it's not clear to me how Go suits a web application with relational data. From what I've gleaned, an ORM does not make sense in Go, so how would this type of application be approached? Writing a lot of ORM-type boiler-plate? A completely different way? Or is Golang a bad choice for such an application?
- zkirill 12y agoIt's definitely possible but it seems like it's too early for any ORM "best practices". Check out gorp (https://github.com/coopernurse/gorp https://github.com/coopernurse/gorp) and beego orm (https://github.com/astaxie/beego/tree/master/orm https://github.com/astaxie/beego/tree/master/orm) for inspiration. In our case, we had to write a lot of ORM boilerplate.
- sagichmal 12y agoI suppose the Go philosophy would discourage developers from tightly coupling Go types and their relational representations through an ORM. The idiomatic way of mapping your objects to a database is by defining a thin interface around a sql.DB, with first-class operations for your concrete types. type User struct { ID int Permalink string } type Storage sql.DB Then you can either do func (s *Storage) WriteUser(user User) error { if _, err := s.Exec( "REPLACE INTO users VALUES (?, ?)", user.ID, user.Permalink, ); err != nil { return fmt.Errorf("write user failed: %s", err) } return nil } or func (u User) Write(storage Storage) error { if _, err := storage.Exec( "REPLACE INTO users VALUES (?, ?)", u.ID, u.Permalink, ); err != nil { return fmt.Errorf("write user failed: %s", err) } return nil } It's a bit more laborious in the sense of keystrokes, but it's also more explicit, which is, on balance and over the lifetime of a large software project, a good thing.
- gnaritas 12y agoYuk, that's just manually doing what ORMs give you automatically; that's not a good thing, you're being a human compiler.
- DennisP 12y agoIf you think you're ready, it might be fun to submit a techempower benchmark. http://www.techempower.com/benchmarks/ http://www.techempower.com/benchmarks/
- zkirill 12y agoGreat job! It definitely feels like a microframework compared to others. I'm glad that there are so many starting points for Go web services available now of varying levels complexity. To me this feels like it fills the void between Gorilla and Revel/Martini/Beego. Also, the code is very well documented and easy to follow.
- gfalcao 12y agoWere you inspired by this ? http://www.cherrypy.org/ http://www.cherrypy.org/ The juxtaposition of things and colors and code simplicity looks like so
- jodiscr 12y agoI ain't switching from Perl 5.8 to golang until a shared hosting provider becomes available.
- julien_c 12y agoGoogle App Engine
- tete 12y agoHow does this compare with Martini? http://martini.codegangsta.io/ http://martini.codegangsta.io/
- deleted 12y ago[deleted]
- aalpbalkan 12y agoIt is good to have many web microframeworks in a language ecosystem. In Python probably there are a hundred of those. Many of those are not picked up by the community –a natural selection. Only really a few of those survived. It all depends on you if you are going to choose Revel, Martini, Goji or whatever you want. Today, thousands of apps run on web.py, yet most of the source code is untouched last 3-5 years (https://github.com/webpy/webpy/tree/master/web https://github.com/webpy/webpy/tree/master/web) It's impressive it just works! Personally, I am looking for frameworks that many people rely on, maintained frequently as needed and works just fine. There could be a +-10% difference on QPS those framework URL routers can handle and render a 'hello world' page. So this is a nice attempt I would say, looks cleaner than Martini, still supports middlewares. On the other hand, Martini has support to serve static files, logging, panic recovery, which are also good and has a bigger fanboy community around it: https://github.com/go-martini/martini https://github.com/go-martini/martini
- zenazn 12y agoStatic files: http://golang.org/pkg/net/http/#FileServer http://golang.org/pkg/net/http/#FileServer Logging: http://golang.org/pkg/log/ http://golang.org/pkg/log/ Panic recovery: https://godoc.org/github.com/zenazn/goji/web/middleware#Recoverer https://godoc.org/github.com/zenazn/goji/web/middleware#Reco... Not as many fanboys though (yet!)
- mcescalante 12y agoEvery time I see a web framework for Go, I just want to see an example or two of a website developed with it. Does anybody have any solid examples? Hopefully, like me, some others enjoy exploring existing code as well as reading the examples / docs.
- codegangsta 12y agoI can't speak for Goji. But one popular open source Martini app is Gogs https://github.com/gogits/gogs https://github.com/gogits/gogs
- codegangsta 12y agoLooks very nice. I do appreciate having more clean, well thought out web frameworks in the Go space. Type switches for your handlers is a good way to approach the net/http compatibility. There are some people that find that Martini is a bit too magical for them, and that is completely okay. It's great to see another minimal framework that will suit their needs.
- nemothekid 12y agoI see why some would call Martini "magic" but I'm not entirely sure I prefer having to deal with a giant `map[string]inteface{}`. What you are really doing is moving the "magic" from the framework and onto the developer (I now have to do type checking and casting). That said I'm a huge fan of Martini and I actually use codegangsta's Inject in my other projects to manage shared state/resources, so I am heavily partial to it.
- zenazn 12y agoYeah, this is a good question, and the unfortunate answer is that it was an engineering tradeoff. I wrote a pretty long reply to cypriss (https://news.ycombinator.com/item?id=7632956 https://news.ycombinator.com/item?id=7632956) which I think covers this.
- abbot2 12y agoWhen I read things like "func Get(pattern interface{}, handler interface{})" I start questioning why this whole thing is ever written in Go at all? This kind of ditches half of Go's benefits by moving all type checks to run time.
- zenazn 12y agoIf Go supported method overloading, you could actually write the types of those functions out. The first one is either a string or a regexp.Regexp, and the second one is one of four variations on an http.Handler, giving a total of 8 varieties of each function. I decided that the sin of exposing an interface{} as a parameter was less egregious than the sin of multiplying Goji's API surface area by a factor of 8, but you'll be happy to know that passing a value of the wrong type causes the invocation of Get (Post, etc.) to fatally exit immediately. If you're defining all your routes in a single goroutine before calling goji.Serve() (which is probably the most common way to define routes), your application will crash before it even binds to the socket. So, not quite as good as a guarantee enforced at compile time, but it'll have to do.
- abbot2 12y agoDon't get me wrong, I perfectly understand what interface{} is and why someone is tempted to use it. It just kills the type checking and converts your golang code to a compiled python, without all those nice static analysis things. Yes, API would be larger, but it would be compile time type-checked and you wouldn't depend on things like "well, it will most probably crash very early enough".
- sagichmal 12y agoI totally agree with the parent: far better to have 8 methods doing the same thing with different names and statically-typed parameters, than 1 method taking interface{}s. Strong +1 to a change in API.
- levosmetalo 12y agoJust a quick look at the examples, and I can say that it reminds me very much of Clojure Ring. It provides really small and extensible core, and if the community pick it up and start writing useful middlewares, it can become very useful.
- Matrixik 12y agoAbout this part in README: > I have very little interest in boosting Goji's router's benchmark scores. There is an obvious solution here--radix trees--and maybe if I get bored I'll implement one for Goji, but I think the API guarantees and conceptual simplicity Goji provides are more important (all routes are attempted, one after another, until a matching route is found). Even if I choose to optimize Goji's router, Goji's routing semantics will not change. Maybe you can just use HttpRouter without reimplementing it yourself? https://github.com/julienschmidt/httprouter https://github.com/julienschmidt/httprouter > The router is optimized for best performance and a small memory footprint. It scales well even with very long pathes and a large number of routes. A compressing dynamic trie (radix tree) structure is used for efficient matching. goji.Get("/hello/:name", hello) router := httprouter.New() router.GET("/hello/:name", Hello)
- zenazn 12y agoHuh. I'm not sure I saw that particular project during my search. It looks neat! Without having looked in detail at httprouter, I think the most obvious reason it might not be sufficient is that it doesn't support regular expressions. This might not be a dealbreaker, but I'm fond of the occasional regex route, and I'd have to think long and hard about whether it's worth giving up for a faster router. And plus, I'm still not sure router speed actually matters for most applications. In any event, I do have a long plane trip coming up, and I'm sure Goji will grow itself something at least slightly more efficient than a linear scan then. I'm think Goji's router and middleware stack are already zero-allocation, so it'll just be finding a way to binary search through routes.
- Matrixik 12y agoYou can find benchmarks in pull request for https://github.com/cypriss/golang-mux-benchmark https://github.com/cypriss/golang-mux-benchmark: https://github.com/cypriss/golang-mux-benchmark/pull/5 https://github.com/cypriss/golang-mux-benchmark/pull/5 (the last one)
- ya3r 12y agoDo we yet have the Django for Go? Goji is as said a microframework, what I want is an equivalent of Django.
- hackerboos 12y agoI doubt this will be produced. Microframeworks written in Go are more likely to replace Django Rest Framework [1] than Django itself [1] http://www.django-rest-framework.org/ http://www.django-rest-framework.org/
- gkya 12y agoCall it nitpicking, but I would rather not export a symbol 'C' from a library I write. Seriously, is 'Context' that hard to type? And the author seems to be far from lazy, the codebase is nicely and extensively commented (it is a nice read indeed). Apart from this issue, the library seems quite nice.