1
0
mirror of https://github.com/labstack/echo.git synced 2025-01-12 01:22:21 +02:00
Signed-off-by: Vishal Rana <vr@labstack.com>
This commit is contained in:
Vishal Rana 2015-04-07 13:02:23 -07:00
parent cff9ce5ae6
commit a95d6668f3
7 changed files with 51 additions and 77 deletions

View File

@ -16,7 +16,7 @@ Echo is a fast HTTP router (zero memory allocation) + micro web framework in Go.
- `http.Handler`
- `http.HandlerFunc`
- `func(http.ResponseWriter, *http.Request)`
- Sub/Group routing
- Group routing
- Handy encoding/decoding functions.
- Serve static files, including index.

View File

@ -2,7 +2,6 @@ package echo
import (
"encoding/json"
"html/template"
"net/http"
"strings"
)
@ -36,34 +35,27 @@ func (c *Context) Param(name string) (value string) {
}
// Bind decodes the body into provided type based on Content-Type header.
func (c *Context) Bind(i interface{}) error {
func (c *Context) Bind(v interface{}) error {
ct := c.Request.Header.Get(HeaderContentType)
if strings.HasPrefix(ct, MIMEJSON) {
return json.NewDecoder(c.Request.Body).Decode(i)
return json.NewDecoder(c.Request.Body).Decode(v)
} else if strings.HasPrefix(ct, MIMEForm) {
return nil
}
return ErrUnsupportedMediaType
}
// Render encodes the provided type and sends a response with status code
// based on Accept header. If Accept header not set, it defaults to html/plain.
func (c *Context) Render(code int, i interface{}) error {
a := c.Request.Header.Get(HeaderAccept)
if strings.HasPrefix(a, MIMEJSON) {
return c.JSON(code, i)
} else if strings.HasPrefix(a, MIMEText) {
return c.String(code, i.(string))
} else if strings.HasPrefix(a, MIMEHTML) {
}
return c.HTMLString(code, i.(string))
func (c *Context) Render(code int, name string, data interface{}) error {
c.Response.Header().Set(HeaderContentType, MIMEHTML+"; charset=utf-8")
c.Response.WriteHeader(code)
return c.echo.renderFunc(c.Response.ResponseWriter, name, data)
}
// JSON sends an application/json response with status code.
func (c *Context) JSON(code int, i interface{}) error {
func (c *Context) JSON(code int, v interface{}) error {
c.Response.Header().Set(HeaderContentType, MIMEJSON+"; charset=utf-8")
c.Response.WriteHeader(code)
return json.NewEncoder(c.Response).Encode(i)
return json.NewEncoder(c.Response).Encode(v)
}
// String sends a text/plain response with status code.
@ -74,20 +66,14 @@ func (c *Context) String(code int, s string) (err error) {
return
}
// HTMLString sends a text/html response with status code.
func (c *Context) HTMLString(code int, html string) (err error) {
// HTML sends a text/html response with status code.
func (c *Context) HTML(code int, html string) (err error) {
c.Response.Header().Set(HeaderContentType, MIMEHTML+"; charset=utf-8")
c.Response.WriteHeader(code)
_, err = c.Response.Write([]byte(html))
return
}
// HTML applies the template associated with t that has the given name to
// the specified data object and sends a text/html response with status code.
func (c *Context) HTML(code int, t *template.Template, name string, data interface{}) (err error) {
return t.ExecuteTemplate(c.Response, name, data)
}
// func (c *Context) File(code int, file, name string) {
// }
@ -106,8 +92,8 @@ func (c *Context) Redirect(code int, url string) {
http.Redirect(c.Response, c.Request, url, code)
}
func (c *Context) reset(rw http.ResponseWriter, r *http.Request, e *Echo) {
c.Response.reset(rw)
func (c *Context) reset(w http.ResponseWriter, r *http.Request, e *Echo) {
c.Response.reset(w)
c.Request = r
c.echo = e
}

View File

@ -3,7 +3,6 @@ package echo
import (
"bytes"
"encoding/json"
"html/template"
"net/http"
"net/http/httptest"
"testing"
@ -67,36 +66,27 @@ func TestContext(t *testing.T) {
t.Error("user name should be Joe")
}
//************//
// Render //
//************//
// JSON
r.Header.Set(HeaderAccept, MIMEJSON)
if err := c.Render(http.StatusOK, u1); err != nil {
if err := c.JSON(http.StatusOK, u1); err != nil {
t.Errorf("render json %v", err)
}
// String
r.Header.Set(HeaderAccept, MIMEText)
c.Response.committed = false
if err := c.Render(http.StatusOK, "Hello, World!"); err != nil {
if err := c.String(http.StatusOK, "Hello, World!"); err != nil {
t.Errorf("render string %v", err)
}
// HTML string
// HTML
r.Header.Set(HeaderAccept, MIMEHTML)
c.Response.committed = false
if err := c.Render(http.StatusOK, "Hello, <strong>World!</strong>"); err != nil {
if err := c.HTML(http.StatusOK, "Hello, <strong>World!</strong>"); err != nil {
t.Errorf("render html %v", err)
}
// HTML
c.Response.committed = false
tmpl, _ := template.New("foo").Parse(`{{define "T"}}Hello, {{.}}!{{end}}`)
if err := c.HTML(http.StatusOK, tmpl, "T", "Joe"); err != nil {
t.Errorf("render html template %v", err)
}
// Redirect
c.Response.committed = false
c.Redirect(http.StatusMovedPermanently, "http://labstack.github.io/echo")
}

29
echo.go
View File

@ -2,6 +2,7 @@ package echo
import (
"errors"
"io"
"log"
"net/http"
"sync"
@ -14,12 +15,14 @@ type (
middleware []MiddlewareFunc
maxParam byte
notFoundHandler HandlerFunc
renderFunc RenderFunc
pool sync.Pool
}
Middleware interface{}
MiddlewareFunc func(HandlerFunc) HandlerFunc
Handler interface{}
HandlerFunc func(*Context)
RenderFunc func(io.Writer, string, interface{}) error
)
const (
@ -69,6 +72,9 @@ func New() (e *Echo) {
notFoundHandler: func(c *Context) {
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.pool.New = func() interface{} {
@ -86,20 +92,15 @@ func New() (e *Echo) {
func (h HandlerFunc) ServeHTTP(http.ResponseWriter, *http.Request) {
}
// Sub creates a new sub router. It inherits all properties from the parent
// router, including middleware.
func (e *Echo) Sub(pfx string) *Echo {
s := *e
s.prefix = pfx
return &s
}
// Group is similar to Sub but excludes inheriting middleware from the parent
// router.
func (e *Echo) Group(pfx string) *Echo {
// Group creates a sub router. It inherits all properties from the parent.
// Passing middleware overrides parent middleware.
func (e *Echo) Group(pfx string, m ...Middleware) *Echo {
g := *e
g.prefix = pfx
g.middleware = nil
if len(m) > 0 {
g.middleware = nil
g.Use(m...)
}
return &g
}
@ -190,7 +191,7 @@ func (e *Echo) Index(file string) {
e.ServeFile("/", file)
}
func (e *Echo) ServeHTTP(rw 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)
defer e.pool.Put(c)
if echo != nil {
@ -199,7 +200,7 @@ func (e *Echo) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
if h == nil {
h = e.notFoundHandler
}
c.reset(rw, r, e)
c.reset(w, r, e)
// Middleware
for i := len(e.middleware) - 1; i >= 0; i-- {
h = e.middleware[i](h)

View File

@ -143,27 +143,13 @@ func TestEchoHandler(t *testing.T) {
}
}
func TestEchoSubGroup(t *testing.T) {
func TestEchoGroup(t *testing.T) {
b := new(bytes.Buffer)
e := New()
e.Use(func(*Context) {
b.WriteString("1")
})
e.Get("/users", func(*Context) {})
s := e.Sub("/sub")
s.Use(func(*Context) {
b.WriteString("2")
})
s.Get("/home", func(*Context) {})
g := e.Group("/group")
g.Use(func(*Context) {
b.WriteString("3")
})
g.Get("/home", func(*Context) {})
w := httptest.NewRecorder()
r, _ := http.NewRequest(GET, "/users", nil)
e.ServeHTTP(w, r)
@ -171,17 +157,28 @@ func TestEchoSubGroup(t *testing.T) {
t.Errorf("should only execute middleware 1, executed %s", b.String())
}
// Group
g1 := e.Group("/group1")
g1.Use(func(*Context) {
b.WriteString("2")
})
g1.Get("/home", func(*Context) {})
b.Reset()
w = httptest.NewRecorder()
r, _ = http.NewRequest(GET, "/sub/home", nil)
r, _ = http.NewRequest(GET, "/group1/home", nil)
e.ServeHTTP(w, r)
if b.String() != "12" {
t.Errorf("should execute middleware 1 & 2, executed %s", b.String())
}
// Group with no parent middleware
g2 := e.Group("/group2", func(*Context) {
b.WriteString("3")
})
g2.Get("/home", func(*Context) {})
b.Reset()
w = httptest.NewRecorder()
r, _ = http.NewRequest(GET, "/group/home", nil)
r, _ = http.NewRequest(GET, "/group2/home", nil)
e.ServeHTTP(w, r)
if b.String() != "3" {
t.Errorf("should execute middleware 3, executed %s", b.String())

View File

@ -65,7 +65,7 @@ func (r *response) Size() int {
return r.size
}
func (r *response) reset(rw http.ResponseWriter) {
r.ResponseWriter = rw
func (r *response) reset(w http.ResponseWriter) {
r.ResponseWriter = w
r.committed = false
}

View File

@ -214,10 +214,10 @@ func (r *router) Find(method, path string) (h HandlerFunc, c *Context, echo *Ech
}
}
func (r *router) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
func (r *router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
h, c, _ := r.Find(req.Method, req.URL.Path)
defer r.echo.pool.Put(c)
c.Response.ResponseWriter = rw
c.Response.ResponseWriter = w
if h != nil {
h(c)
} else {