Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Building REST API with GoLang

Burak Aydın
November 29, 2015

Building REST API with GoLang

Burak Aydın

November 29, 2015
Tweet

More Decks by Burak Aydın

Other Decks in Technology

Transcript

  1. #dfist Performance • “Rewriting the EventMachine push backend to Go

    we went from 250k connections per node to 1.5 million connections per node” • “Full integration test suite dropped from 25 minutes to 2 minutes.” • “The time to do a full API server deploy with rolling restarts dropped from 30 minutes to 3 minutes” http://blog.parse.com/learn/how-we-moved-our-api-from-ruby-to-go-and-saved-our-sanity/
  2. #dfist Go Lang • Static Typed • Interfaces, types, structs

    • Garbage Collection • Concurrency The gopher is covered under Creative Commons Attribution 3.0 license. They were designed by Renée French, who also designed Glenda, the Plan 9 bunny. Additional info can be found here.
  3. #dfist Basic Middleware func main() { http.HandleFunc("/hello", handleHello) log.Fatal(http.ListenAndServe("localhost:8080", nil))

    } func handleHello(w http.ResponseWriter, req *http.Request) { fmt.Fprintln(w, "Hello, 世界!") } main.go
  4. #dfist Gorilla Mux - github.com/gorilla/mux Routing func main() { r

    := mux.NewRouter() v1 := r.PathPrefix("/api/v1").Subrouter() v1.Methods("GET").Path("/shops").Handler(route.ListShopsHandler) http.ListenAndServe(":8080", v1) } main.go
  5. #dfist http.Handler func ListShopsHandler(w http.ResponseWriter, r *http.Request) { q :=

    ctx.M(r).DB("").C("shops").Find(nil) shops := []model.Shop{} err := q.All(&shops) // error handling w.WriteHeader(http.StatusOK) err = json.NewEncoder(w).Encode(shops) if err != nil { log.Println(err) } } shop.go
  6. #dfist http.Handler type Handler interface { ServeHTTP(ResponseWriter, *Request) } //

    The HandlerFunc type is an adapter to allow the use of // ordinary functions as HTTP handlers. If f is a function // with the appropriate signature, HandlerFunc(f) is a // Handler object that calls f. type HandlerFunc func(ResponseWriter, *Request) // ServeHTTP calls f(w, r). func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) { f(w, r) }
  7. #dfist http.Handler signature func(w http.ResponseWriter, r *http.Request) Avoid using global

    variables, share values over context • Adapter Pattern • Chain Packages • Complex handlers • Handler Closures
  8. #dfist Adapter Pattern type Adapter func(http.Handler) http.Handler func Logging(l *log.Logger)

    Adapter { return func(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { l.Println(r.Method, r.URL.Path) h.ServeHTTP(w, r) }) } } adapter.go
  9. #dfist Adapter Pattern func Adapt(h http.Handler, adapters ...Adapter) http.Handler {

    for _, adapter := range adapters { h = adapter(h) } return h } func main() { l := log.New(os.Stdout, "server:", log.Lshortfile) db, _ := mgo.Dial("localhost") defer db.Close() http.Handle("/", Adapt(http.HandlerFunc(index), Mongo(db), Logging(l), Cors)) http.ListenAndServe("localhost:8080", nil) } func index(rw http.ResponseWriter, req *http.Request) { fmt.Fprint(rw, "Hello world") } adapter.go
  10. #dfist Adapter Pattern with context func Mongo(dbSession *mgo.Session) Adapter {

    return func(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { dbcopy := dbSession.Copy() defer dbcopy.Close() context.Set(r, "db", dbcopy) h.ServeHTTP(w, r) }) } } adapter.go Gorilla Context - github.com/gorilla/context
  11. #dfist Adapter Pattern with context func handleThingsRead(w http.ResponseWriter, r *http.Request)

    { db := context.Get(r, "db").(*mgo.Session) s, _ := db.DatabaseNames() fmt.Fprint(w, s) } adapter.go
  12. #dfist Chain Sample var ( appChain = chain.New( mware.Mongo, mware.Cors,

    Logger) ) func handler() http.Handler { r := mux.NewRouter() v1 := r.PathPrefix("/api/v1").Subrouter() v1.Methods("GET").Path("/shops").Handler(appChain.ThenFunc(route.ListShopsHandler)) return v1 } routes.go
  13. #dfist Complex Handlers Don’t break http.handler interface! func handleThingsRead(w http.ResponseWriter,

    r *http.Request, db *mgo.Session) { s, _ := db.DatabaseNames() fmt.Fprint(w, s) } main.go
  14. #dfist Http Closures gist.github.com/tsenart/5fc18c659814c078378d func main() { db, err :=

    sql.Open("postgres", "…") if err != nil { log.Fatal(err) } logger := log.New(os.Stdout, "", 0) http.Handle("/hello", withMetrics(logger, helloHandler(db))) http.ListenAndServe(":8080", nil) } main.go
  15. #dfist JSON in Go func Marshal(v interface{}) ([]byte, error) func

    Unmarshal(data []byte, v interface{}) error func (dec *Decoder) Decode(v interface{}) error func (enc *Encoder) Encode(v interface{}) error encoding/json
  16. #dfist JSON in Go Interface maps raw_data := []byte(`{"msg": "Hello

    Go!", "id": 12345}`) decoded := map[string]interface{}{} err := json.Unmarshal(raw_data, &decoded) if err != nil { log.Fatal(err) } fmt.Println(decoded["msg"].(string), int(decoded["id"].(float64)))
  17. #dfist JSON in Go Exported struct with tag type ExportedMessageWithTags

    struct { Msg string `json:"msg"` Id int64 `json:"id"` } func WithTags() { raw_data := []byte(`{"msg": "Hello Go!", "id": 12345}`) decoded := ExportedMessageWithTags{} err := json.Unmarshal(raw_data, &decoded) if err != nil { log.Fatal(err) } fmt.Println(decoded.Msg, decoded.Id) }
  18. #dfist JSON in Go Try to use Interface and json.RawMessage

    combination for complex json const input = ` { "type": "sound", "msg": { "description": "dynamite", "authority": "the Bruce Dickinson" } }` type Envelope struct { Type string Msg interface{} } type Sound struct { Description string Authority string }
  19. #dfist JSON in Go var msg json.RawMessage env := Envelope{

    Msg: &msg, } if err := json.Unmarshal([]byte(input), &env); err != nil { log.Fatal(err) } switch env.Type { case "sound": var s Sound if err := json.Unmarshal(msg, &s); err != nil { log.Fatal(err) } var desc string = s.Description fmt.Println(desc) default: log.Fatalf("unknown message type: %q", env.Type) }
  20. #dfist Respond github.com/unrolled/render func main() { r := render.New(render.Options{}) mux

    := http.NewServeMux() // This will set the Content-Type header to "application/json; charset=UTF-8". mux.HandleFunc("/json", func(w http.ResponseWriter, req *http.Request) { r.JSON(w, http.StatusOK, map[string]string{"hello": "json"}) }) http.ListenAndServe("127.0.0.1:3000", mux) }
  21. #dfist Web Frameworks • Negroni • Gin • Beego •

    Revel github.com/avelino/awesome-go#web-frameworks
  22. #dfist Other Subjects • Go routine • Channels • Database

    • Auth • Error • JWT • Microservices • Test