
A RESTful Micro-Framework in Go - Nogwater
http://dougblack.io/words/a-restful-micro-framework-in-go.html
======
mitchellh
This 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.

~~~
hierro
We're about to release our Go web framework which, I think, implements all the
features you're mentioning and a few more. We're aiming for a release in Q1,
but getting everything cleaned up and writing good documentation is taking a
bit longer than expected. Right now, our internal framework (codenamed
Gondola, but subject to change), includes:

* A full ORM which generates tables from structs and allows relations between models, as well as a simple querying system based on Go functions which joins the tables automatically for you e.g.
    
    
       memeId := base36.Decode(param)
       var meme *Meme
       var template *Template
       err := ctx.Orm().One(orm.Eq("Meme|Id", memeId), &meme, &template)
    

Meme declares a FK to Template, so the ORM automatically joins the tables and
populates both pointers. Note that the ORM does not require the backends to be
relational, so even when ATM we only have database/sql based backends you
could write a backend for mongodb or rethinkdb.

* Inheritance based template system, with a declarative assets pipeline supporting compilation (e.g. it compiles coffescript to JS and less to CSS on demand - also pluggable). This is the base template from one of our apps:
    
    
       {{/*
          jquery|if=~ie-gte-9: 2.0.3
          jquery|if=ie: 1.10.2
          bootstrap|fontawesome=4.0.3: 3.0.0
          styles|bundle: css/style.css, lightbox/css/lightbox.css
          scripts|top,bundle: js/modernizr.js, js/detectizr.js
          scripts|bundle: js/responsiveslides.js, lightbox/js/lightbox-2.6.min.js, js/site.js
          analytics|nodebug: {{ $Config.Analytics }}
       */}}
        <!DOCTYPE html>
        ...
        {{ template "main" }}...
    

This server query 1.10 and 2.0 from Google's CDN, bootstrap and fontawesome
from bootstrapcdn.com and bundles all our styles and scripts a CSS and a JS
file. Then other templates can extend this one and override its blocks e.g.

    
    
       {{/*
         extends: base.html
       */}} 
       {{ define "main" }}...
    

(note that base.html could also define its own "main" block which would act as
a default if you loaded base.html and it would be replaced by main.html's
"main" block if you loaded "main").

* Easy to use signed and encrypted cookies.

* Regular expression based URL routing.

* Functions for easily parsing input parameters.

* A development server which automatically rebuilds the source as it changes and reports compilation errors in the browser itself. While developing, runtime errors are also reported in the browser with complete backtraces and printing the values passed to each function. While running in production, those reports are sent by email to the project administrator(s).

* App-wide and low-level caching system with pluggable backends, currently supporting Redis and Memcache as well as a dummy backend for development.

* Form generator and validator from Go structs, with renderers for both Bootstrap and Foundation (renderers are also pluggable, so you could also write your own. We also support generating forms from multiple objects so you e.g. write an object which generates a captcha and include it in any form with a single line in code (in fact, we provide just that, but a simple numeric captcha a a full-blown recaptcha object). It also does automatic CSRF protection.

* A complete i18n system, which extracts strings from Go code and templates, generates .pot files which can be translated using any editor (or a specialized .po editor if you feel like it) and them compiles .po files back to Go code again. This makes packages with their translations "go-get-able".

* Periodic and background tasks which can either be scheduled or just started from any web request.

* A configuration package which takes a struct and fills it by parsing an optional configuration file as well as command line flags.

* Support for administrative commands, which can be executed from the command line or started remotely.

* Support for pluggable apps. e.g. we do have a "users" app which provides user registration, authentication and social integration. This can be included in any other app with a couple of lines of code (one line for the import, another line to tell our main app to include it). Included apps can do a lot of stuff, like inserting code in every template rendered by the parent app, including external assets like images, styles or scripts and even rendering their own templates contained inside your parent's app base template.

* Last but not least, a minimal overhead (in the range of 100ns per request) profiling framework which lets you know how much time a request spent in the cache, the orm, the template, e.g... as well as seeing how much each operation took (e.g. you can check how much time a SELECT took and also perform an EXPLAIN on it). Users can also define their own events and profile them by instrumenting their code (it usually requires just a line of code per resource, to indicate its name). You can also profile a live server by using a command line app included in the framework.

We also have helper and utility functions for the more mundane stuff and
basically everything you could expect from a web framework. We took
inspiration from Django, Tornado and Rails and tried to take the best of them
while building this framework (I used to contribute to Tornado back in the
day). We've been developing this internally for almost 2 years and it's now
around 40KLOC of Go and a couple of K of coffescript, less and html.

~~~
chrissnell
That sounds incredible. Where can I follow news about your release?

~~~
hierro
I'll send a message to golang-nuts to announce it as soon as it gets released.

~~~
jksmith
Hopefully the ORM is not a lock-in for the framework. Good old sql calls have
their place.

~~~
hierro
We support hand written SQL queries, in fact we are using them because the ORM
still does not have all the features like e.g. Django's ORM.

------
tptacek
This 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.

~~~
carbocation
I agree with you re: the lack of ORMs in golang. I actually enjoy writing and
profiling my own SQL, but if I want to prototype, ORMs can speed up the
process.

I will say that some of the parts of SQL in golang that I find most annoying,
such as populating structs, are handled very nicely by jmoiron's sqlx library.
[1] This is not an ORM, but it's an extension to sql that removes some of the
most annoying boilerplate nevertheless.

1 = [https://github.com/jmoiron/sqlx](https://github.com/jmoiron/sqlx)

~~~
jamra
This looks like an awesome library. I like how he does this:

type Person struct { FirstName string `db:"first_name"` LastName string
`db:"last_name"` Email string }

to map columns to structs.

------
natural219
This 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.

------
polymathist
I 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
You 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.

------
_ak
Nice, 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.

------
dclara
I 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++?

------
mjallday
Languages 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.

------
jevinskie
I appreciated the development narrative rather than a post-project summary.
Thanks!

------
jrockway
Drive-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.".

------
cronos
Why 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
Author.

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.

------
swah
Kinda off-topic, but would you write a real-time web application in Go today?

~~~
tptacek
We did. Worked well.

~~~
swah
I'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.

------
dark_ph0enix
I'm yet to test this, but any idea how it compares against Martini?

~~~
macu
It 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

------
skj
Wonderfully small, easy to grok, and put into practice.

