1
0
mirror of https://github.com/labstack/echo.git synced 2024-12-24 20:14:31 +02:00
Signed-off-by: Vishal Rana <vr@labstack.com>
This commit is contained in:
Vishal Rana 2015-04-28 23:09:30 -07:00
parent 6a1ba5883c
commit 02ca5e4443
5 changed files with 94 additions and 59 deletions

View File

@ -65,19 +65,19 @@ func (c *Context) JSON(code int, v interface{}) error {
} }
// String sends a text/plain response with status code. // String sends a text/plain response with status code.
func (c *Context) String(code int, s string) (err error) { func (c *Context) String(code int, s string) error {
c.Response.Header().Set(HeaderContentType, MIMEText+"; charset=utf-8") c.Response.Header().Set(HeaderContentType, MIMEText+"; charset=utf-8")
c.Response.WriteHeader(code) c.Response.WriteHeader(code)
_, err = c.Response.Write([]byte(s)) _, err := c.Response.Write([]byte(s))
return return err
} }
// HTML sends a text/html response with status code. // HTML sends a text/html response with status code.
func (c *Context) HTML(code int, html string) (err error) { func (c *Context) HTML(code int, html string) 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)
_, err = c.Response.Write([]byte(html)) _, err := c.Response.Write([]byte(html))
return return err
} }
// NoContent sends a response with no body and a status code. // NoContent sends a response with no body and a status code.

View File

@ -144,7 +144,7 @@ func New() (e *Echo) {
return return
} }
// Group creates a new sub router with prefix and inherits all properties from // Group creates a new sub router with prefix. It inherits all properties from
// the parent. Passing middleware overrides parent middleware. // the parent. Passing middleware overrides parent middleware.
func (e *Echo) Group(pfx string, m ...Middleware) *Echo { func (e *Echo) Group(pfx string, m ...Middleware) *Echo {
g := *e g := *e

View File

@ -13,11 +13,11 @@ type (
prefix string prefix string
parent *node parent *node
children children children children
pchild *node // Param child // pchild *node // Param child
cchild *node // Catch-all child // mchild *node // Match-any child
handler HandlerFunc handler HandlerFunc
pnames []string pnames []string
echo *Echo echo *Echo
} }
ntype uint8 ntype uint8
children []*node children []*node
@ -26,7 +26,7 @@ type (
const ( const (
stype ntype = iota stype ntype = iota
ptype ptype
ctype mtype
) )
func NewRouter(e *Echo) (r *router) { func NewRouter(e *Echo) (r *router) {
@ -64,9 +64,8 @@ func (r *router) Add(method, path string, h HandlerFunc, echo *Echo) {
} }
r.insert(method, path[:i], nil, ptype, pnames, echo) r.insert(method, path[:i], nil, ptype, pnames, echo)
} else if path[i] == '*' { } else if path[i] == '*' {
r.insert(method, path[:i], nil, stype, nil, echo)
pnames = append(pnames, "_name") pnames = append(pnames, "_name")
r.insert(method, path[:l], h, ctype, pnames, echo) r.insert(method, path[:i], h, mtype, pnames, echo)
return return
} }
} }
@ -201,7 +200,7 @@ func (n *node) findPchild() *node {
func (n *node) findCchild() *node { func (n *node) findCchild() *node {
for _, c := range n.children { for _, c := range n.children {
if c.typ == ctype { if c.typ == mtype {
return c return c
} }
} }
@ -226,16 +225,21 @@ func (r *router) Find(method, path string, ctx *Context) (h HandlerFunc, echo *E
c := new(node) // Child node c := new(node) // Child node
n := 0 // Param counter n := 0 // Param counter
// Search order static > param > catch-all // Search order static > param > match-any
for { for {
if search == "" || search == cn.prefix { if search == "" || search == cn.prefix || cn.typ == mtype {
if cn.handler != nil { // Found
// Found h = cn.handler
h = cn.handler echo = cn.echo
ctx.pnames = cn.pnames ctx.pnames = cn.pnames
echo = cn.echo
return // Match-any
if cn.typ == mtype {
println(search, cn.prefix)
ctx.pvalues[0] = search[len(cn.prefix):]
} }
return
} }
pl := len(cn.prefix) pl := len(cn.prefix)
@ -247,11 +251,6 @@ func (r *router) Find(method, path string, ctx *Context) (h HandlerFunc, echo *E
goto Up goto Up
} }
// Catch-all with empty value
if len(search) == 0 {
goto CatchAll
}
// Static node // Static node
c = cn.findSchild(search[0]) c = cn.findSchild(search[0])
if c != nil { if c != nil {
@ -274,17 +273,6 @@ func (r *router) Find(method, path string, ctx *Context) (h HandlerFunc, echo *E
continue continue
} }
// Catch-all node
CatchAll:
// c = cn.cchild
c = cn.findCchild()
if c != nil {
cn = c
ctx.pvalues[n] = search
search = "" // End search
continue
}
Up: Up:
tn := cn // Save current node tn := cn // Save current node
cn = cn.parent cn = cn.parent

View File

@ -326,19 +326,24 @@ func TestRouterTwoParam(t *testing.T) {
return nil return nil
}, nil) }, nil)
h, _ := r.Find(GET, "/users/1/files/1", context) // h, _ := r.Find(GET, "/users/1/files/1", context)
if h == nil { // if h == nil {
t.Fatal("handler not found") // t.Fatal("handler not found")
} // }
if context.pvalues[0] != "1" { // if context.pvalues[0] != "1" {
t.Error("param uid should be 1") // t.Error("param uid should be 1")
} // }
if context.pvalues[1] != "1" { // if context.pvalues[1] != "1" {
t.Error("param fid should be 1") // t.Error("param fid should be 1")
// }
h, _ := r.Find(GET, "/users/1", context)
if h != nil {
t.Error("should not found handler")
} }
} }
func TestRouterCatchAll(t *testing.T) { func TestRouterMatchAny(t *testing.T) {
r := New().Router r := New().Router
r.Add(GET, "/users/*", func(*Context) error { r.Add(GET, "/users/*", func(*Context) error {
return nil return nil
@ -349,6 +354,7 @@ func TestRouterCatchAll(t *testing.T) {
t.Fatal("handler not found") t.Fatal("handler not found")
} }
if context.pvalues[0] != "" { if context.pvalues[0] != "" {
println(context.pvalues[0])
t.Error("value should be joe") t.Error("value should be joe")
} }

View File

@ -39,8 +39,8 @@ for many use cases. Restricting path parameters allows us to use memory efficien
`echo.NotFoundHandler(h Handler)` `echo.NotFoundHandler(h Handler)`
Registers a custom NotFound handler used by Registers a custom NotFound handler. This handler is called in case router doesn't
router in case it doesn't find any registered handler for HTTP method and path. find matching route for the request.
Default handler sends 404 "Not Found" response. Default handler sends 404 "Not Found" response.
@ -70,6 +70,12 @@ echo.Get("/hello", func(*echo.Context) {
}) })
``` ```
Echo's default handler is `func(*echo.Context) error` where `echo.Context` primarily
holds request and response objects. Echo also has a support for other types of
handlers.
<!-- TODO mention about not able to take advantage -->
<!-- ### Groups --> <!-- ### Groups -->
### Path parameters ### Path parameters
@ -90,7 +96,7 @@ echo.Get("/users/:id", func(c *echo.Context) {
}) })
``` ```
### Match any ### Match-any
Matches zero or more characters in the path. For example, pattern `/users/*` will Matches zero or more characters in the path. For example, pattern `/users/*` will
match match
@ -100,14 +106,36 @@ match
- `/users/1/files/1` - `/users/1/files/1`
- `/users/anything...` - `/users/anything...`
<!-- Test it -->
### Path matching order ### Path matching order
- Static - Static
- Param - Param
- Match any - Match any
#### Example
```go
e.Get("/users/:id", func(c *echo.Context) {
c.String(http.StatusOK, "/users/:id")
})
e.Get("/users/new", func(c *echo.Context) {
c.String(http.StatusOK, "/users/new")
})
e.Get("/users/1/files/*", func(c *echo.Context) {
c.String(http.StatusOK, "/users/1/files/*")
})
```
Above routes would resolve in order
- `/users/new`
- `/users/:id`
- `/users/1/files/*`
Routes can be written in any order.
<!-- Different use cases --> <!-- Different use cases -->
### URI building ### URI building
@ -128,13 +156,24 @@ h := func(*echo.Context) {
e.Get("/users/:id", h) e.Get("/users/:id", h)
``` ```
<!-- ## Request -->
<!-- ## Middleware --> <!-- ## Middleware -->
<!-- ## Response --> ## Response
## Static Content ### JSON
`context.JSON(code int, v interface{}) error` can be used to send a JSON response
with status code.
### String
`context.String(code int, s string) error` can be used to send plain text response
with status code.
### HTML
`func (c *Context) HTML(code int, html string) error` can be used to send an HTML
response with status code.
### Static files ### Static files
@ -165,3 +204,5 @@ e.Index("index.html")
``` ```
<!-- ## Error Handling --> <!-- ## Error Handling -->
<!-- Deployment -->