Slide 1

Slide 1 text

3 secrets to build web APIs in Go Matt Aimonetti - splice.com - @mattetti

Slide 2

Slide 2 text

Matt Aimonetti splice: Go, Ruby, JS, Obj-C, C#, C++, C golangbootcamp.com

Slide 3

Slide 3 text

Splice

Slide 4

Slide 4 text

Splice

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

Architecture clients APIs / core logic web rendering

Slide 9

Slide 9 text

Architecture Web API: Synchronization File upload File download Notifications Obj-C C# C Go

Slide 10

Slide 10 text

Architecture file parsing/analysis (sessions, media) deduplication/storage intermediate representation

Slide 11

Slide 11 text

Architecture internal/private API (application logic) “public” API (states retrieval/change)

Slide 12

Slide 12 text

Architecture HTTP Message Bus Long running async tasks

Slide 13

Slide 13 text

Go vs Ruby 10-20% slower to write 20-100x faster to run 60-80% less maintenance required batteries included

Slide 14

Slide 14 text

• Deployment • Routing • Monitoring

Slide 15

Slide 15 text

No content

Slide 16

Slide 16 text

Deployment Zero downtime deployments bitbucket.org/splice/go.grace careful with goroutines

Slide 17

Slide 17 text

Deployment Version Control CI Storage

Slide 18

Slide 18 text

Deployment

Slide 19

Slide 19 text

Deployment 2014-06-23-183000/api 2014-06-23-204500/api current/api symlink

Slide 20

Slide 20 text

Deployment 2014-06-23-183000/api 2014-06-23-204500/api current/api $ kill -USR2 {api PID} symlink

Slide 21

Slide 21 text

No content

Slide 22

Slide 22 text

Routing var V42Routes = Endpoints{ // create Ableton Live session { Verb: "POST", Path: "/v42/live/sessions", Handler: handlers.AlsUpload, RequiredParams: handlers.AlsUploadReqParams, Auth: splice.ClientAuth, }, // create Logic session { Verb: "POST", Path: "/v42/logic/sessions", Handler: handlers.LogicUpload, RequiredParams: handlers.LogicUploadReqParams, Auth: splice.ClientAuth, }, }

Slide 23

Slide 23 text

Routing package router type Endpoint struct { Verb string Path string RequiredParams []string Auth func(*splice.ReqEnv, bool) bool Handler splice.Handler }

Slide 24

Slide 24 text

Routing type Endpoints []Endpoint // Activate all the endpoint API routes. func (es Endpoints) Activate(p *pat.PatternServeMux) { for _, e := range es { // [..] set authentication calls // [..] check param requirements handler := splice.ReqWrap(e.Handler, e.Auth) p.Add(e.Verb, e.Path, handler) // [..] collect all CORS verbs accepted for this endpoint so we can create OPTIONS routes. } }

Slide 25

Slide 25 text

Routing func ReqWrap(handler *Handler, checkAuthFn func(*ReqEnv, bool) bool) http.Handler { ! return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { start := time.Now() defer reportRequest(req, start, handler.Metrics) reqUuid := uuid.GenUUID() req := &ReqEnv{ ReqUuid: reqUuid, Request: r, Response: &statusResponseWriter{w, 0}, } // [..] set headers (content type, req ID, build) if !checkAuthFn(req, checkAuth) { return } ! ! !

Slide 26

Slide 26 text

Routing ! ! ! // We must return a 400 and stop here if there was a problem // parsing the request. err := req.ParseParams() if err != nil { // […]return 400 return } // convert a panic into a 500 defer req.handlePanic() handler.Handle(req) }) }

Slide 27

Slide 27 text

No content

Slide 28

Slide 28 text

Monitoring Monitor all the things! runtime.ReadMemStats http://golang.org/pkg/runtime/#MemStats

Slide 29

Slide 29 text

Lessons learned low memory usage

Slide 30

Slide 30 text

Lessons learned detect issues

Slide 31

Slide 31 text

Lessons learned detect issues

Slide 32

Slide 32 text

Low memory usage use streaming io.Reader/io.Writer io.Copy Encoder/Decoder instead of ReadAll and Unmarshal

Slide 33

Slide 33 text

Monitoring Monitor all the things! Per endpoint: • # of requests • Status codes • Response times

Slide 34

Slide 34 text

No content

Slide 35

Slide 35 text

@mattetti http://matt.aimonetti.net