Package rest is a RESTful web-service framework. It make function to http.Handler automatically.
I want to make a clear, flexible framework, which easy to write and test. Here is some principle when I design go-rest:
-
Don't repeat yourself.
The framework will grab as many as it can to set up service. No need to specify "postdata" type or "output" type which has defined in handler.
-
Handle HTTP directly if you want.
Handler support http.Handler or http.HandleFunc directly, so you can add old style handler, like http.FileServer directly.
-
Handle HTTP request right.
Use Accept to check mime. If Accept doesn't exist, use service default mime.
-
Work with other framework.
Package go-rest will work with GAE or net/http or any other framework working with http.Handler.
-
Speed.
Golang is fast, framework should be fast too.
-
Easy to do unit test.
No need to worry about marshal and unmarshal when do unit test, handler function is normal function, test it directly.
$ go get github.com/googollee/go-rest
http://godoc.org/github.com/googollee/go-rest
package main
import (
"fmt"
"github.com/googollee/go-rest"
"net/http"
"strings"
)
func main() {
r := rest.New()
// add log midware
r.Use(rest.NewLog(nil))
// add router. router must before mime parser because parser need handler's parameter inserted by router.
r.Use(rest.NewRouter())
// support mime of text/html and application/json
html, err := rest.NewHTML("./templates")
if err != nil {
fmt.Println("html template error:", err)
return
}
r.Use(rest.NewMimeParser(html, rest.NewJSON()))
// simple handler
r.Get("/", func() (map[string]interface{}, string) {
return map[string]interface{}{"name": "rest"}, "hello"
})
// rest handler, name from post body
r.Get("/hello.js", func(name string) map[string]interface{} {
return map[string]interface{}{
"action": "hello",
"name": name,
}
})
// handle url parameter.
r.Get("/hello/:name", func(params rest.Params) (map[string]interface{}, string) {
return params, "hello"
})
// handle url parameter and post body, and return error if invalid.
r.Post("/json/:id", func(params rest.Params, i int) (map[string]interface{}, error) {
if params["id"] == nil {
return nil, rest.Error(http.StatusBadRequest, "id is empty")
}
id, ok := params["id"].(string)
if !ok {
return nil, rest.Error(http.StatusBadRequest, "id is not string")
}
if id == "" {
return nil, rest.Error(http.StatusBadRequest, "id is empty")
}
return map[string]interface{}{
"id": id,
"request": i,
}, nil
})
// handle static file
r.NotFound(prefix("/static/"), http.FileServer(http.Dir(".")))
// launch http server
http.ListenAndServe("127.0.0.1:8080", r)
}
// custom midware
func prefix(prefix string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if !strings.HasPrefix(r.URL.Path, prefix) {
http.NotFound(w, r)
return
}
}
}