Slide 1

Slide 1 text

No content

Slide 2

Slide 2 text

Slide 3

Slide 3 text

◦ ◦ ◦ ◦ ◦ ◦

Slide 4

Slide 4 text

func h(w http.ResponseWriter, r *http.Request) { } Boilerplate code (logging, auth, parameters) Boilerplate code (response writing, etc) Main handler code

Slide 5

Slide 5 text

func h(w http.ResponseWriter, r *http.Request) { f(w, r) { } g(w, r) { } } Boilerplate code (logging, auth, parameters) Boilerplate code (response writing, etc) Main handler code

Slide 6

Slide 6 text

func f(w http.ResponseWriter, r *http.Request) { } func h(w http.ResponseWriter, r *http.Request) { } func g(w http.ResponseWriter, r *http.Request) { } Boilerplate code (logging, auth, parameters) Boilerplate code (response writing, etc) Main handler code

Slide 7

Slide 7 text

func(c siesta.Context, w http.ResponseWriter, r *http.Request) { // set interface{}s c.Set("foo", bar); // get interface{}s c.Get("foo") // => interface{}(bar) } ◦ ◦

Slide 8

Slide 8 text

gorilla/context ◦ ◦ ◦ func MyHandler(w http.ResponseWriter, r *http.Request) { // ... requestID := context.Get(r, "request-id") // ... }

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

func (s *Service) ServeHTTPInContext(c Context, w http.ResponseWriter, r *http.Request) { // ... quit := false for _, m := range s.pre { // s.pre is a slice of handlers m(c, w, r, func() { quit = true }) if quit { break } } // ... }

Slide 13

Slide 13 text

flags ◦ GET /resources/:resourceID/things?all=true ◦ params.Int("resourceID", …) ◦ params.Bool("all", …)

Slide 14

Slide 14 text

var params siesta.Params // GET /resources/:resourceID/... resourceID := params.Int("resourceID", -1, "Resource identifier") err := params.Parse(r.Form) if err != nil { // Do something with the err } // Make sure we have a valid resource ID. if *resourceID == -1 { // Handle the invalid resource }

Slide 15

Slide 15 text

No content

Slide 16

Slide 16 text

No content

Slide 17

Slide 17 text

// responseGenerator converts response and/or error data passed through the // context into a structured response. func responseGenerator(c siesta.Context, w http.ResponseWriter, r *http.Request) { response := apiResponse{} if data := c.Get("data"); data != nil { response.Data = data } if err := c.Get("error"); err != nil { response.Error = err.(string) } c.Set("response", response) }

Slide 18

Slide 18 text

func TestHandler(t *testing.T) { c := siesta.NewSiestaContext() // c.Set(...) myHandler(c, mockResponseWriter, &http.Request{ Form: url.Values(map[string][]string{ "id": []string{"1"}, // maybe a GET /resource/:id }), } // c.Get(...) }

Slide 19

Slide 19 text

database/sql ◦ ◦ ◦ ◦

Slide 20

Slide 20 text

Slide 21

Slide 21 text

sql.DB sql.Tx sql. DB sql.Tx ◦ database/sql sql.DB sql.Tx

Slide 22

Slide 22 text

sql.DB type SQLDB interface { Query(query string, args ...interface{}) (SQLRows, error) QueryRow(query string, args ...interface{}) SQLRow Exec(query string, args ...interface{}) (sql.Result, error) Begin() error Rollback() error Commit() error } type SQLRows interface { SQLRow Close() error Err() error Next() bool } type SQLRow interface { Scan(dest ...interface{}) error }

Slide 23

Slide 23 text

type DB struct { sqlDB *sql.DB tx *sql.Tx context siesta.Context } func (db *DB) Query(query string, args ...interface{}) (Rows, error) { // db.context is accessible! if db.tx != nil { return db.tx.Query(query, args...) } return db.sqlDB.Query(query, args...) } // ...

Slide 24

Slide 24 text

No content

Slide 25

Slide 25 text

$ curl localhost:8080/resources/1 -u abcde: { "data": "foo" } $ curl localhost:8080/resources/1?usage -u abcde: { "data": { "resourceID": [ "resourceID", "int", "Resource identifier" ], "usage": [ "usage", "bool", "Show usage" ] } } Name Type Description

Slide 26

Slide 26 text

// Check parameters var params siesta.Params resourceID := params.Int("resourceID", -1, "Resource identifier") params.Bool("usage", false, "Show usage") if r.URL.Query()["usage"] != nil { c.Set("data", params.Usage()) return } err := params.Parse(r.Form) // ...

Slide 27

Slide 27 text

/resources/:resourceID?summary=true { "method": "GET", "url": [ { "name": "resources", "type": "fixed" }, { "name": "resourceID", "type": "parameter" "parameterType": "int", "description": "Resource ID" } ], "queryString": [ { "name": "summary", "parameterType": "bool", "description": "Show only feature summary" } ], "endpoint": "/resources/:resourceID" }