mirror of
https://github.com/labstack/echo.git
synced 2024-12-24 20:14:31 +02:00
parent
6a1ba5883c
commit
02ca5e4443
12
context.go
12
context.go
@ -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.
|
||||||
|
2
echo.go
2
echo.go
@ -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
|
||||||
|
42
router.go
42
router.go
@ -13,8 +13,8 @@ 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
|
||||||
@ -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
|
||||||
ctx.pnames = cn.pnames
|
|
||||||
echo = cn.echo
|
echo = cn.echo
|
||||||
return
|
ctx.pnames = cn.pnames
|
||||||
|
|
||||||
|
// 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
|
||||||
|
@ -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")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 -->
|
||||||
|
Loading…
Reference in New Issue
Block a user