mirror of
https://github.com/labstack/echo.git
synced 2025-01-12 01:22:21 +02:00
parent
cff9ce5ae6
commit
a95d6668f3
@ -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.
|
||||
|
||||
|
38
context.go
38
context.go
@ -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
|
||||
}
|
||||
|
@ -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
29
echo.go
@ -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)
|
||||
|
31
echo_test.go
31
echo_test.go
@ -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())
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user