siesta: a different go framework

27

Upload: vividcortex

Post on 21-Jan-2018

279 views

Category:

Technology


0 download

TRANSCRIPT

func h(w http.ResponseWriter, r *http.Request) {

}

Boilerplate code (logging, auth, parameters)

Boilerplate code (response writing, etc)

Main handler code

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

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

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

}

◦◦

gorilla/context◦

◦◦

func MyHandler(w http.ResponseWriter, r *http.Request) {

// ...

requestID := context.Get(r, "request-id")

// ...

}

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

}

}// ...

}

flags

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

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}

// 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)

}

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(...)

}

database/sql

◦◦◦◦

sql.DB sql.Txsql.

DB sql.Tx

◦ database/sqlsql.DB sql.Tx

sql.DBtype 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

}

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...)

}

// ...

$ 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"

]

}

}

NameTypeDescription

// Check parametersvar params siesta.ParamsresourceID := 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)// ...

/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"

}