Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Updated server to use reorganized code with helpers
- Loading branch information
Showing
17 changed files
with
495 additions
and
2,650 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
(function() { | ||
|
||
var ListView = Backbone.View.extend({ | ||
el: $('body'); // attaches 'this.el' to an existing element | ||
|
||
initialize: function() { | ||
_.bindAll(this, 'render'); // fixes loss of context for 'this' within methods | ||
|
||
this.render(); | ||
} | ||
|
||
render: function() { | ||
$(this.el).append("<ul><li>hello world</li></ul>"); | ||
} | ||
}); | ||
|
||
var listView = new ListView(); | ||
|
||
})(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
// The controllers represent the actions that can be | ||
// taken with the web application. | ||
package helpers | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"github.com/hoisie/web" | ||
"io/ioutil" | ||
) | ||
|
||
// A Controller for a corresponding Backbone Model object. | ||
type Controller interface { | ||
// Create model object based on parameters | ||
// attr is a json-formatted string of attributes | ||
// Return a json-formattable object of all model attributes | ||
Create(attr string) (interface{}, error) | ||
// Read a model object back | ||
// ID may be empty string | ||
// Return a json-formattable object of all model attributes | ||
Read(id string) (interface{}, error) | ||
// Update a model object based on parameters. | ||
// ID is required and will be non-empty | ||
// attr is a json-formatted string of attributes | ||
// Return a json-formattable object of updated model attributes | ||
// If no attributes other than the updated ones changed, it is acceptable to return nil | ||
Update(id, attr string) (interface{}, error) | ||
// Delete a model object. | ||
// ID is required and will be non-empty | ||
Delete(id string) error | ||
} | ||
|
||
type Context struct { | ||
*web.Context | ||
} | ||
|
||
func (ctx *Context) readBody() (string, error) { | ||
str, err := ioutil.ReadAll(ctx.Request.Body) | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
return string(str), nil | ||
} | ||
|
||
func (ctx *Context) writeJson(m interface{}) { | ||
str, err := json.Marshal(m) | ||
if err != nil { | ||
ctx.Abort(500, "Error marshalling map: "+err.Error()) | ||
} | ||
ctx.WriteString(string(str)) | ||
} | ||
|
||
func (ctx *Context) writeError(err error) { | ||
ctx.WriteHeader(400) | ||
rv := map[string]string{ | ||
"error": err.Error(), | ||
} | ||
str, err2 := json.Marshal(rv) | ||
if err2 != nil { | ||
ctx.Abort(500, fmt.Sprintf("Error mashalling error(%s): %s", err.Error(), err2.Error())) | ||
} | ||
ctx.WriteString(string(str)) | ||
} | ||
|
||
func BindController(svr *web.Server, path string, ctrl Controller) { | ||
// Create | ||
svr.Post(path, func(wctx *web.Context) { | ||
ctx := &Context{wctx} | ||
body, err := ctx.readBody() | ||
if err != nil { | ||
ctx.writeError(err) | ||
return | ||
} | ||
|
||
ret, err := ctrl.Create(body) | ||
if err != nil { | ||
ctx.writeError(err) | ||
return | ||
} | ||
|
||
ctx.writeJson(ret) | ||
}) | ||
|
||
// Read | ||
svr.Get(path+"/?(.*)", func(wctx *web.Context, id string) { | ||
ctx := &Context{wctx} | ||
ret, err := ctrl.Read(id) | ||
if err != nil { | ||
ctx.writeError(err) | ||
return | ||
} | ||
|
||
ctx.writeJson(ret) | ||
}) | ||
|
||
// Update | ||
svr.Put(path+"/(.+)", func(wctx *web.Context, id string) { | ||
ctx := &Context{wctx} | ||
body, err := ctx.readBody() | ||
|
||
if err != nil { | ||
ctx.writeError(err) | ||
return | ||
} | ||
|
||
ret, err := ctrl.Update(id, body) | ||
if err != nil { | ||
ctx.writeError(err) | ||
return | ||
} | ||
|
||
// Accept nil responses | ||
if ret != nil { | ||
ctx.writeJson(ret) | ||
} else { | ||
ctx.NotModified() | ||
} | ||
}) | ||
|
||
// Delete | ||
svr.Delete(path+"/(.+)", func(wctx *web.Context, id string) { | ||
ctx := &Context{wctx} | ||
err := ctrl.Delete(id) | ||
if err != nil { | ||
ctx.writeError(err) | ||
return | ||
} | ||
|
||
ctx.NotModified() | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
package helpers | ||
|
||
import ( | ||
"bytes" | ||
"encoding/json" | ||
"fmt" | ||
"github.com/hoisie/web" | ||
"io" | ||
"net/http" | ||
"testing" | ||
"time" | ||
) | ||
|
||
const ( | ||
port int = 16123 | ||
path string = "/test" | ||
) | ||
|
||
type ExampleController map[string]string | ||
|
||
func (e ExampleController) Create(attr string) (interface{}, error) { | ||
return e, nil | ||
} | ||
func (e ExampleController) Read(id string) (interface{}, error) { | ||
return e, nil | ||
} | ||
func (e ExampleController) Update(id, attr string) (interface{}, error) { | ||
return e, nil | ||
} | ||
func (e ExampleController) Delete(id string) error { | ||
return nil | ||
} | ||
|
||
func ExampleInitController(svr *web.Server, path string) { | ||
m := map[string]string{"hello": "world"} | ||
ctrl := ExampleController(m) | ||
|
||
BindController(svr, path, ctrl) | ||
} | ||
|
||
func init() { | ||
svr := web.NewServer() | ||
ExampleInitController(svr, path) | ||
go svr.Run(fmt.Sprintf("0.0.0.0:%d", port)) | ||
<-time.After(10 * time.Millisecond) | ||
} | ||
|
||
func checkRespBody(t *testing.T, r io.Reader) { | ||
m := map[string]string{} | ||
j := json.NewDecoder(r) | ||
err := j.Decode(&m) | ||
if err != nil { | ||
t.Error("Response Body was not decodable into json", err) | ||
} else if m["hello"] != "world" { | ||
t.Error("Response Body did not contain correct map", m) | ||
} | ||
} | ||
|
||
func TestCreate(t *testing.T) { | ||
url := fmt.Sprintf("http://127.0.0.1:%d%s", port, path) | ||
client := &http.Client{} | ||
|
||
cbody := bytes.NewBuffer([]byte(`{}`)) | ||
creq, err := http.NewRequest("POST", url, cbody) | ||
if err != nil { | ||
t.Fatal("Error creating the create request", err) | ||
} | ||
cres, err := client.Do(creq) | ||
if err != nil { | ||
t.Fatal("Error performing create request", err) | ||
} | ||
defer cres.Body.Close() | ||
checkRespBody(t, cres.Body) | ||
} | ||
|
||
func TestRead(t *testing.T) { | ||
url := fmt.Sprintf("http://127.0.0.1:%d%s/id", port, path) | ||
client := &http.Client{} | ||
|
||
creq, err := http.NewRequest("GET", url, nil) | ||
if err != nil { | ||
t.Fatal("Error creating the create request", err) | ||
} | ||
cres, err := client.Do(creq) | ||
if err != nil { | ||
t.Fatal("Error performing create request", err) | ||
} | ||
defer cres.Body.Close() | ||
checkRespBody(t, cres.Body) | ||
} | ||
|
||
func TestUpdate(t *testing.T) { | ||
url := fmt.Sprintf("http://127.0.0.1:%d%s/id", port, path) | ||
client := &http.Client{} | ||
|
||
creq, err := http.NewRequest("PUT", url, nil) | ||
if err != nil { | ||
t.Fatal("Error creating the create request", err) | ||
} | ||
cres, err := client.Do(creq) | ||
if err != nil { | ||
t.Fatal("Error performing create request", err) | ||
} | ||
defer cres.Body.Close() | ||
checkRespBody(t, cres.Body) | ||
} | ||
|
||
func TestDelete(t *testing.T) { | ||
url := fmt.Sprintf("http://127.0.0.1:%d%s/id", port, path) | ||
client := &http.Client{} | ||
|
||
creq, err := http.NewRequest("DELETE", url, nil) | ||
if err != nil { | ||
t.Fatal("Error creating the create request", err) | ||
} | ||
cres, err := client.Do(creq) | ||
if err != nil { | ||
t.Fatal("Error performing create request", err) | ||
} | ||
defer cres.Body.Close() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package helpers | ||
|
||
import ( | ||
"github.com/hoisie/web" | ||
"io/ioutil" | ||
"log" | ||
) | ||
|
||
// Web.go handler to serve static files | ||
// This should not be used in production | ||
func ServeStatic(root string, svr *web.Server) { | ||
svr.Get("/static(.*)", | ||
func(ctx *web.Context, path string) { | ||
fn := root + path | ||
log.Printf("Serving static file %s", fn) | ||
data, err := ioutil.ReadFile(fn) | ||
if err != nil { | ||
ctx.NotFound("File not found!") | ||
log.Println("Could not read file!", err) | ||
return | ||
} | ||
|
||
ctx.WriteString(string(data)) | ||
}) | ||
} |
Oops, something went wrong.