1
0
mirror of https://github.com/labstack/echo.git synced 2025-06-06 23:46:16 +02:00

New renderer interface #21

Signed-off-by: Vishal Rana <vr@labstack.com>
This commit is contained in:
Vishal Rana 2015-04-09 14:59:31 -07:00
parent da18bc1ce6
commit 6633a1fca7
6 changed files with 316 additions and 309 deletions

View File

@ -48,7 +48,7 @@ func (c *Context) Bind(v interface{}) error {
func (c *Context) Render(code int, name string, data interface{}) error { func (c *Context) Render(code int, name string, data interface{}) error {
c.Response.Header().Set(HeaderContentType, MIMEHTML+"; charset=utf-8") c.Response.Header().Set(HeaderContentType, MIMEHTML+"; charset=utf-8")
c.Response.WriteHeader(code) c.Response.WriteHeader(code)
return c.echo.renderFunc(c.Response, name, data) return c.echo.renderer.Render(c.Response, name, data)
} }
// JSON sends an application/json response with status code. // JSON sends an application/json response with status code.

View File

@ -12,7 +12,7 @@ func TestContext(t *testing.T) {
b, _ := json.Marshal(u1) b, _ := json.Marshal(u1)
r, _ := http.NewRequest(POST, "/users/1", bytes.NewReader(b)) r, _ := http.NewRequest(POST, "/users/1", bytes.NewReader(b))
c := &Context{ c := &Context{
Response: &response{writer: httptest.NewRecorder()}, Response: &response{Writer: httptest.NewRecorder()},
Request: r, Request: r,
params: make(Params, 5), params: make(Params, 5),
store: make(store), store: make(store),

18
echo.go
View File

@ -15,14 +15,16 @@ type (
middleware []MiddlewareFunc middleware []MiddlewareFunc
maxParam byte maxParam byte
notFoundHandler HandlerFunc notFoundHandler HandlerFunc
renderFunc RenderFunc renderer Renderer
pool sync.Pool pool sync.Pool
} }
Middleware interface{} Middleware interface{}
MiddlewareFunc func(HandlerFunc) HandlerFunc MiddlewareFunc func(HandlerFunc) HandlerFunc
Handler interface{} Handler interface{}
HandlerFunc func(*Context) HandlerFunc func(*Context)
RenderFunc func(io.Writer, string, interface{}) error Renderer interface {
Render(io.Writer, string, interface{}) error
}
) )
const ( const (
@ -72,9 +74,6 @@ func New() (e *Echo) {
notFoundHandler: func(c *Context) { notFoundHandler: func(c *Context) {
http.Error(c.Response, http.StatusText(http.StatusNotFound), http.StatusNotFound) http.Error(c.Response, http.StatusText(http.StatusNotFound), http.StatusNotFound)
}, },
renderFunc: func(w io.Writer, name string, data interface{}) (err error) {
return
},
} }
e.Router = NewRouter(e) e.Router = NewRouter(e)
e.pool.New = func() interface{} { e.pool.New = func() interface{} {
@ -115,9 +114,9 @@ func (e *Echo) NotFoundHandler(h Handler) {
e.notFoundHandler = wrapH(h) e.notFoundHandler = wrapH(h)
} }
// RenderFunc sets a custom RenderFunc. // Renderer sets an HTML Renderer.
func (e *Echo) RenderFunc(r RenderFunc) { func (e *Echo) Renderer(r Renderer) {
e.renderFunc = r e.renderer = r
} }
// Use adds handler to the middleware chain. // Use adds handler to the middleware chain.
@ -197,7 +196,8 @@ func (e *Echo) Index(file string) {
} }
func (e *Echo) ServeHTTP(w http.ResponseWriter, r *http.Request) { func (e *Echo) ServeHTTP(w http.ResponseWriter, r *http.Request) {
h, c, echo := e.Router.Find(r.Method, r.URL.Path) c := e.pool.Get().(*Context)
h, echo := e.Router.Find(r.Method, r.URL.Path, c.params)
if echo != nil { if echo != nil {
e = echo e = echo
} }

View File

@ -7,7 +7,7 @@ import (
type ( type (
response struct { response struct {
writer http.ResponseWriter Writer http.ResponseWriter
status int status int
size int size int
committed bool committed bool
@ -15,7 +15,7 @@ type (
) )
func (r *response) Header() http.Header { func (r *response) Header() http.Header {
return r.writer.Header() return r.Writer.Header()
} }
func (r *response) WriteHeader(n int) { func (r *response) WriteHeader(n int) {
@ -25,12 +25,12 @@ func (r *response) WriteHeader(n int) {
return return
} }
r.status = n r.status = n
r.writer.WriteHeader(n) r.Writer.WriteHeader(n)
r.committed = true r.committed = true
} }
func (r *response) Write(b []byte) (n int, err error) { func (r *response) Write(b []byte) (n int, err error) {
n, err = r.writer.Write(b) n, err = r.Writer.Write(b)
r.size += n r.size += n
return n, err return n, err
} }
@ -44,6 +44,6 @@ func (r *response) Size() int {
} }
func (r *response) reset(w http.ResponseWriter) { func (r *response) reset(w http.ResponseWriter) {
r.writer = w r.Writer = w
r.committed = false r.committed = false
} }

View File

@ -157,8 +157,7 @@ func lcp(a, b string) (i int) {
return return
} }
func (r *router) Find(method, path string) (h HandlerFunc, c *Context, echo *Echo) { func (r *router) Find(method, path string, params Params) (h HandlerFunc, echo *Echo) {
c = r.echo.pool.Get().(*Context)
cn := r.trees[method] // Current node as root cn := r.trees[method] // Current node as root
search := path search := path
n := 0 // Param count n := 0 // Param count
@ -182,7 +181,7 @@ func (r *router) Find(method, path string) (h HandlerFunc, c *Context, echo *Ech
i, l := 0, len(search) i, l := 0, len(search)
for ; i < l && search[i] != '/'; i++ { for ; i < l && search[i] != '/'; i++ {
} }
p := c.params[:n+1] p := params[:n+1]
p[n].Name = cn.prefix[1:] p[n].Name = cn.prefix[1:]
p[n].Value = search[:i] p[n].Value = search[:i]
n++ n++
@ -190,7 +189,7 @@ func (r *router) Find(method, path string) (h HandlerFunc, c *Context, echo *Ech
} else if cn.has == cnode { } else if cn.has == cnode {
// Catch-all node // Catch-all node
cn = cn.edges[0] cn = cn.edges[0]
p := c.params[:n+1] p := params[:n+1]
p[n].Name = "_name" p[n].Name = "_name"
p[n].Value = search p[n].Value = search
search = "" // End search search = "" // End search
@ -215,8 +214,9 @@ func (r *router) Find(method, path string) (h HandlerFunc, c *Context, echo *Ech
} }
func (r *router) ServeHTTP(w http.ResponseWriter, req *http.Request) { func (r *router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
h, c, _ := r.Find(req.Method, req.URL.Path) c := r.echo.pool.Get().(*Context)
c.Response.writer = w h, _ := r.Find(req.Method, req.URL.Path, c.params)
c.Response.Writer = w
if h != nil { if h != nil {
h(c) h(c)
} else { } else {

View File

@ -12,7 +12,9 @@ type route struct {
path string path string
} }
var api = []route{ var (
params = make(Params, 5)
api = []route{
// OAuth Authorizations // OAuth Authorizations
{"GET", "/authorizations"}, {"GET", "/authorizations"},
{"GET", "/authorizations/:id"}, {"GET", "/authorizations/:id"},
@ -274,11 +276,12 @@ var api = []route{
//{"PATCH", "/user/keys/:id"}, //{"PATCH", "/user/keys/:id"},
{"DELETE", "/user/keys/:id"}, {"DELETE", "/user/keys/:id"},
} }
)
func TestRouterStatic(t *testing.T) { func TestRouterStatic(t *testing.T) {
r := New().Router r := New().Router
r.Add(GET, "/folders/files/echo.gif", func(*Context) {}, nil) r.Add(GET, "/folders/files/echo.gif", func(*Context) {}, nil)
h, _, _ := r.Find(GET, "/folders/files/echo.gif") h, _ := r.Find(GET, "/folders/files/echo.gif", params)
if h == nil { if h == nil {
t.Fatal("handle not found") t.Fatal("handle not found")
} }
@ -286,35 +289,37 @@ func TestRouterStatic(t *testing.T) {
func TestRouterParam(t *testing.T) { func TestRouterParam(t *testing.T) {
r := New().Router r := New().Router
r.Add(GET, "/users/:id", func(*Context) {}, nil) r.Add(GET, "/users/:id", func(c *Context) {
h, c, _ := r.Find(GET, "/users/1")
if h == nil {
t.Fatal("handle not found")
}
if c.P(0) != "1" { if c.P(0) != "1" {
t.Error("param id should be 1") t.Error("param id should be 1")
} }
}, nil)
h, _ := r.Find(GET, "/users/1", make(Params, 5))
if h == nil {
t.Fatal("handle not found")
}
} }
func TestRouterTwoParam(t *testing.T) { func TestRouterTwoParam(t *testing.T) {
r := New().Router r := New().Router
r.Add(GET, "/users/:uid/files/:fid", func(*Context) {}, nil) r.Add(GET, "/users/:uid/files/:fid", func(c *Context) {
h, c, _ := r.Find(GET, "/users/1/files/1")
if h == nil {
t.Fatal("handle not found")
}
if c.P(0) != "1" { if c.P(0) != "1" {
t.Error("param uid should be 1") t.Error("param uid should be 1")
} }
if c.P(1) != "1" { if c.P(1) != "1" {
t.Error("param fid should be 1") t.Error("param fid should be 1")
} }
}, nil)
h, _ := r.Find(GET, "/users/1/files/1", params)
if h == nil {
t.Fatal("handle not found")
}
} }
func TestRouterCatchAll(t *testing.T) { func TestRouterCatchAll(t *testing.T) {
r := New().Router r := New().Router
r.Add(GET, "/static/*", func(*Context) {}, nil) r.Add(GET, "/static/*", func(*Context) {}, nil)
h, _, _ := r.Find(GET, "/static/*") h, _ := r.Find(GET, "/static/*", params)
if h == nil { if h == nil {
t.Fatal("handle not found") t.Fatal("handle not found")
} }
@ -322,11 +327,7 @@ func TestRouterCatchAll(t *testing.T) {
func TestRouterMicroParam(t *testing.T) { func TestRouterMicroParam(t *testing.T) {
r := New().Router r := New().Router
r.Add(GET, "/:a/:b/:c", func(*Context) {}, nil) r.Add(GET, "/:a/:b/:c", func(c *Context) {
h, c, _ := r.Find(GET, "/1/2/3")
if h == nil {
t.Fatal("handle not found")
}
if c.P(0) != "1" { if c.P(0) != "1" {
t.Error("param a should be 1") t.Error("param a should be 1")
} }
@ -336,16 +337,17 @@ func TestRouterMicroParam(t *testing.T) {
if c.P(2) != "3" { if c.P(2) != "3" {
t.Error("param c should be 3") t.Error("param c should be 3")
} }
}, nil)
h, _ := r.Find(GET, "/1/2/3", params)
if h == nil {
t.Fatal("handle not found")
}
} }
func TestRouterAPI(t *testing.T) { func TestRouterAPI(t *testing.T) {
r := New().Router r := New().Router
for _, route := range api { for _, route := range api {
r.Add(route.method, route.path, func(*Context) {}, nil) r.Add(route.method, route.path, func(c *Context) {
h, c, _ := r.Find(route.method, route.path)
if h == nil {
t.Errorf("handler not found, method=%s, path=%s", route.method, route.path)
}
for _, p := range c.params { for _, p := range c.params {
if p.Name != "" { if p.Name != "" {
if ":"+p.Name != p.Value { if ":"+p.Name != p.Value {
@ -353,6 +355,11 @@ func TestRouterAPI(t *testing.T) {
} }
} }
} }
}, nil)
h, _ := r.Find(route.method, route.path, params)
if h == nil {
t.Errorf("handler not found, method=%s, path=%s", route.method, route.path)
}
} }
} }