8 ms·
A RESTful Micro-Framework in Go
- mjallday 13y agoLanguages live or die on their libraries. This is great. I sat down to write a quick api in go about three weeks ago but couldn't find a framework that I wanted to use. This looks like it has a decent abstraction and libraries like this really help language adoption. Much thanks to the author of the library.
- skj 13y agoWonderfully small, easy to grok, and put into practice.
- dark_ph0enix 13y agoI'm yet to test this, but any idea how it compares against Martini?
- jjsz 13y agoI don't understand why, when questions like these are asked, they are never answered...
- macu 13y agoIt doesn't have the same aim as Martini, which provides more of a full middleware manager. Sleepy is a simple wrapper for RESTful resources that takes a few steps out of the handler work, e.g. internally handles the work of encoding a response to JSON and then sending it. Nice to see new developers delving in, albeit a little clumsy at first :P
- _ak 13y agoNice, easy to use, really straightforward code. The only thing I would have done differently is make sleepy.Api implement http.Handler so that it would easily integrate with other libraries that build upon and play nicely with net/http.
- swah 13y agoKinda off-topic, but would you write a real-time web application in Go today?
- tptacek 13y agoWe did. Worked well.
- swah 13y agoI'm glad to read that. May I ask what technology did you guys use? SockJS' Python implementation works well (well, I haven't deployed yet...), but the Go port isn't that mature IIRC.
- aninteger 13y agoWorked or did you mean it works? If you meant worked can you further expand on why it no longer works well today?
- jchrisa 13y agoThe Go runtime is still being optimized. For instance we found that the upgrade to Go 1.2 made a big difference for some of our performance tests. So it's nice to get surprises like that but also shows that the ecosystem is still young.
- tptacek 13y agoThis looks like great work, so probably this comment is a little off topic, but here goes anyways: Every web framework I've seen for Golang seems to do a competent job of tackling the easiest part of designing a web framework, which is routing requests to handlers. Actually, the built-in net/http library already does a serviceable job of handling requests, and if you understand closures, filtering them and maintaining request state as well. The thing no framework I have seen so far addresses is persistence. SQL persistence in Golang is a bit of a nightmare. It's raw SQL, and the database libraries are fussy. The thing that makes Rails so easy to write in, especially for newcomers, is ActiveRecord. As far as I can tell, nothing like it exists (in a stable form) for Golang.
- icholy 13y agoIMO having some ORM automagically construct queries for you is a pretty scary idea. Obviously it's not a good idea to have SQL scattered all over your codebase (we've all seen it). But including SQL in your code isn't hard if you keep it in one place and abstract it properly.
- chimeracoder 13y agoI'm going to chime in, since I've been using Go as my primary language for over a year, and I'm currently working on a major (production) Go project that others might see as well-suited for Rails (in fact, the early prototype was written in Rails[0]) > The thing no framework I have seen so far addresses is persistence. SQL persistence in Golang is a bit of a nightmare. It's raw SQL, and the database libraries are fussy. > The thing that makes Rails so easy to write in, especially for newcomers, is ActiveRecord. As far as I can tell, nothing like it exists (in a stable form) for Golang. I wouldn't recommend newcomers to Go use SQL right off the bat. Document-based storage (like CouchDB or MongoDB), or even key/value (Redis, etc.) is much more aligned with Go's concept of structs, and all three of those databases have strong library support in Go. If you're just looking to dabble in Go and just happen to need a database (and it doesn't matter which), I'd recommend playing around with those first. Even Neo4j works very well with Go, though as of January 2013 (when I last used it), the only Go library for Neo4j was third-party, and not very well-documented. That said, once you know the Go language, using SQL (either with or without an ORM) is straightforward, if not as convenient as ActiveRecord. jmoiron has a good blog post[1] comparing the good, bad, and ugly of Go ORMs, so I won't try to top that here - rather, I'll share my experience. (As pointed out elsewhere, ORMs are not universally liked as a general concept, so I'm writing this comparison assuming that one actually does want the features an ORM provides - naturally, if you prefer prepared SQL, Go already provides perfect support for that.) Gorp is definitely not as "magical" as ActiveRecord, but it certainly does the job. A number of the ways in which it differs from ActiveRecord have more to do with the (strongly) static vs. dynamic difference in type systems, though some are specific to Go's architecture. There are a few odd features here and there that are still missing (for example, I'm actually not sure if there's a wrapper function for "INSERT IF NOT EXISTS" yet, though it's not a huge bother). I do end up spending more time thinking about the queries that I'm using, compared to Django or Rails. There is some additional verbosity - I have to write some helper functions that I wouldn't otherwise have to. On the other hand, I know exactly what queries are being executed at all times, so it's easy to identify potential bottlenecks. In short - I agree that ActiveRecord is more convenient than anything that currently exists in Go. On the other hand, it's reasonably advanced enough that relative newcomers to the language[2] shouldn't have a problem with it. So far, the biggest bottleneck in development of this application has not been with the SQL bindings, even though it would be nice to spend a bit less time on that front. It hasn't had as much time to develop and mature as ActiveRecord have, but those of us using it in production have accepted those tradeoffs. [0] If you're wondering why we didn't continue it in Rails, we had to scrap the original codebase for a number of other reasons, so given that we weren't keeping any of the original code, there was no logical reason we needed to use the same language. [1] http://jmoiron.net/blog/golang-orms/ http://jmoiron.net/blog/golang-orms/ [2] As opposed to newcomers to programming in general
- cronos 13y agoWhy exactly do Resource's methods take variadic argument? In what scenario can there be more than one? Also, small remarks about code: You define type HandleFunc in your package which is identical to http.HandlerFunc. Looks like it can be removed. Some error logging (rw.Write, json.Marshal) would be useful as well.
- dougblack 13y agoAuthor. Great points. They don't need to be variadic. I misunderstood the type of url.Values. And I didn't see http.HandlerFunc! I eschewed error logging in the interest of simplicity. Thanks for the corrections! Updating the article now.
- mitchellh 13y agoThis looks like a great resource! A bit of a rant (not directed at the person who wrote this, because the link at hand is great): Writing APIs in Go is not the hard part. There are a ton of options for routing basic URLs to handlers. There are a few areas that are a nightmare, total total nightmare: * SQL - The raw database/sql package in Go is very low-level. It is a terrible experience to use in a project that makes anything more than a handful of simple queries. I'm not asking for an ORM, but it would really benefit the community if there was a SQLAlchemy style (the non-ORM part of it) library for Go. It should be MUCH easier to make basic queries to SQL and get out results. * Templating - The built in "html/template" package is just not good enough for a web app when compared to something like Jinja (Python). "html/template" gets points for being simple, and actually its not a complaint against "html/template": I think there just needs to be a more feature-packed templating package like Jinja for Go. "html/template" doesn't support things like inheritance, didn't even support comparison operators until Go 1.2, etc. These two problems have made it so I've pretty much given up web apps in Go for now. Services in Go are _amazing_. But if you're trying to get a full blown web app (again, not the point of the linked article above), then you're gonna have a bad time.
- chimeracoder 13y ago> "html/template" doesn't support things like inheritance I don't want to get into a debate about what "inheritance" means, but html/template does support template composition and nested templates, which seem to address the same use case. > These two problems have made it so I've pretty much given up web apps in Go for now. Services in Go are _amazing_. But if you're trying to get a full blown web app (again, not the point of the linked article above), then you're gonna have a bad time. I'm sorry to hear that, especially since writing a "full-blown web app" is really not difficult in Go at all, once you know what you're doing. I've actually been working on Jetpack[0], a sample web application in Go to demonstrate how straightforward this is, once one understands how it actually works. (Disclaimer: it's still a work in progress, so it's not complete/ready yet). [0] https://github.com/ChimeraCoder/go-angular-jetpack https://github.com/ChimeraCoder/go-angular-jetpack
- BarkMore 13y ago
- natural219 13y agoThis post really highlights what I like about Go so far vs other languages -- the evolving community. Like Rails, there is an emphasis on abstraction and productivity. Unlike Rails, the blog posts I've seen so far seem to be centered around explaining how to implement the functionality instead of just wrapping the functionality and providing an easy API. Now that I've read this post, I could download his library, implement my own, or extend the parts I want to customize very easily. I feel more powerful.
- jevinskie 13y agoI appreciated the development narrative rather than a post-project summary. Thanks!
- polymathist 13y agoI would have taken a different approach for handling unsupported resource methods. I'd love to hear some feedback on whether or not this is considered idiomatic. Instead of this: type HelloResource struct { sleepy.PostNotSupported sleepy.PutNotSupported sleepy.DeleteNotSupported } Something like this: type HelloResource struct { sleepy.DefaultResponder } DefaultResponder is simply a struct which has all the methods of sleepy.PostNotSupported, sleepy.PutNotSupported, etc, and is defined: type DefaultResponder struct{} func (DefaultResponder) Get(values url.Values) (int, interface{}) { return 405, map[string]string{"error": "Not implemented"} } func (DefaultResponder) Post(values url.Values) (int, interface{}) { return 405, map[string]string{"error": "Not implemented"} } func (DefaultResponder) Put(values url.Values) (int, interface{}) { return 405, map[string]string{"error": "Not implemented"} } func (DefaultResponder) Delete(values url.Values) (int, interface{}) { return 405, map[string]string{"error": "Not implemented"} } Now, if you want to implement resource methods, you define them on the top-level struct, like so: type HelloResource struct { sleepy.DefaultResponder } def (HelloResource) Get(values url.Values) (int, interface{}) { data := map[string]string{"hello": "world"} return 200, data } So now, if you call Get on a HelloResource type, it uses the method defined on HelloResource, not the one defined on it's embedded DefaultResponder type. But if you call HelloResource.Post, it uses the method defined on DefaultResponder, i.e., it returns a 405 error. This is effectively like "overriding" in Java or other object oriented languages and saves a few lines when people are using your library. What do you think? Again, I'm really just looking for feedback here as I too am new to go. Is this something that would be considered idiomatic, or is the original solution better? (Apologies in advance for any typos or syntax errors. Didn't check this with a compiler, but hopefully you get the idea.)
- optymizer1 13y agoYou could even go further and assume all user resources are logical extensions of sleepy.Resource: type HelloResource struct { sleepy.Resource } This makes it clear that you're inheriting everything from sleepy.Resource, so you can provide reasonable implementations for all methods of resources, not just HTTP methods handlers, e.g. getBodyAsJSON(), redirect(resource), etc. Also, depending on how your mux works, you could store app-level data in sleepy.Resource, to be accessed by all resources: sleepy.Resource.DB sleepy.Resource.Session sleepy.Resource.Root and other things I can't think of right now.
- jrockway 13y agoDrive-by code review: I don't see any reason for the Api type to exist. Just make them normal functions? It would also be helpful to print the portstring rather than just "Hi.".
- dclara 13y agoI haven't seen the full picture of Go yet, partially by some examples. I found it makes calling multi-threading functions a lot easier. I consider Ruby, Python, Go and Julia are the new generation of programming languages aiming to be quickly picked up and made hands-on working. Can anybody tell me if Ruby, Python, Go supports a full spectrum of functionalities for various network protocols, multi-threading, messaging (sync and async) and concurrent accessing etc. Those kind of functionalities don't only require additional libraries, but also frameworks and algorithms. Maybe by using Jython, JRuby or something like that, they are able to achieve the complete functionalities like Java. According to some research, Python evolved from Lisp, and Ruby is closed to Perl. So why aren't those script-based language more popular than Java/C++?