Skip to content

Instantly share code, notes, and snippets.

@nmerouze
Created December 5, 2014 12:03

Revisions

  1. nmerouze created this gist Dec 5, 2014.
    117 changes: 117 additions & 0 deletions main.go
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,117 @@
    package main

    import (
    "encoding/json"
    "log"
    "net/http"
    "reflect"
    "time"

    "github.com/gorilla/context"
    "github.com/julienschmidt/httprouter"
    "github.com/justinas/alice"
    "gopkg.in/mgo.v2"
    "gopkg.in/mgo.v2/bson"
    )

    // Repo

    type Tea struct {
    Id bson.ObjectId `json:"id,omitempty" bson:"_id,omitempty"`
    Name string `json:"name"`
    Category string `json:"category"`
    }

    type TeaResource struct {
    Data Tea `json:"data"`
    }

    type TeaRepo struct {
    coll *mgo.Collection
    }

    func (r *TeaRepo) Find(id string) (TeaResource, error) {
    result := TeaResource{}
    err := r.coll.FindId(bson.ObjectIdHex(id)).One(&result.Data)
    if err != nil {
    return result, err
    }

    return result, nil
    }

    type appContext struct {
    db *mgo.Database
    }

    func (c *appContext) teaHandler(w http.ResponseWriter, r *http.Request) {
    params := context.Get(r, "params").(httprouter.Params)
    repo := TeaRepo{c.db.C("teas")}
    tea, err := repo.Find(params.ByName("id"))
    if err != nil {
    panic(err)
    }

    w.Header().Set("Content-Type", "application/vnd.api+json")
    json.NewEncoder(w).Encode(tea)
    }

    func recoverHandler(next http.Handler) http.Handler {
    fn := func(w http.ResponseWriter, r *http.Request) {
    defer func() {
    if err := recover(); err != nil {
    log.Printf("panic: %+v", err)
    http.Error(w, http.StatusText(500), 500)
    }
    }()

    next.ServeHTTP(w, r)
    }

    return http.HandlerFunc(fn)
    }

    func loggingHandler(next http.Handler) http.Handler {
    fn := func(w http.ResponseWriter, r *http.Request) {
    t1 := time.Now()
    next.ServeHTTP(w, r)
    t2 := time.Now()
    log.Printf("[%s] %q %v\n", r.Method, r.URL.String(), t2.Sub(t1))
    }

    return http.HandlerFunc(fn)
    }

    type router struct {
    *httprouter.Router
    }

    func (r *router) Get(path string, handler http.Handler) {
    r.GET(path, wrapHandler(handler))
    }

    func NewRouter() *router {
    return &router{httprouter.New()}
    }

    func wrapHandler(h http.Handler) httprouter.Handle {
    return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
    context.Set(r, "params", ps)
    h.ServeHTTP(w, r)
    }
    }

    func main() {
    session, err := mgo.Dial("localhost")
    if err != nil {
    panic(err)
    }
    defer session.Close()
    session.SetMode(mgo.Monotonic, true)

    appC := appContext{session.DB("test")}
    commonHandlers := alice.New(context.ClearHandler, loggingHandler, recoverHandler)
    router := NewRouter()
    router.Get("/teas/:id", commonHandlers.ThenFunc(appC.teaHandler))
    http.ListenAndServe(":8080", router)
    }