Upload
vividcortex
View
279
Download
0
Embed Size (px)
Citation preview
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(...)
}
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"
}