mirror of
https://github.com/labstack/echo.git
synced 2024-12-24 20:14:31 +02:00
Merge pull request #76 from labstack/websocket
New definition for Echo.HandlerFunc
This commit is contained in:
commit
1e117621e9
53
README.md
53
README.md
@ -9,14 +9,14 @@ Echo is a fast HTTP router (zero memory allocation) and micro web framework in G
|
||||
- `echo.MiddlewareFunc`
|
||||
- `func(echo.HandlerFunc) echo.HandlerFunc`
|
||||
- `echo.HandlerFunc`
|
||||
- `func(*echo.Context) *echo.HTTPError`
|
||||
- `func(*echo.Context) error`
|
||||
- `func(http.Handler) http.Handler`
|
||||
- `http.Handler`
|
||||
- `http.HandlerFunc`
|
||||
- `func(http.ResponseWriter, *http.Request)`
|
||||
- Handler
|
||||
- `echo.HandlerFunc`
|
||||
- `func(*echo.Context) *echo.HTTPError`
|
||||
- `func(*echo.Context) error`
|
||||
- `http.Handler`
|
||||
- `http.HandlerFunc`
|
||||
- `func(http.ResponseWriter, *http.Request)`
|
||||
@ -84,7 +84,7 @@ import (
|
||||
)
|
||||
|
||||
// Handler
|
||||
func hello(c *echo.Context) *echo.HTTPError {
|
||||
func hello(c *echo.Context) error {
|
||||
return c.String(http.StatusOK, "Hello, World!\n")
|
||||
}
|
||||
|
||||
@ -133,34 +133,34 @@ var (
|
||||
// Handlers
|
||||
//----------
|
||||
|
||||
func createUser(c *echo.Context) *echo.HTTPError {
|
||||
func createUser(c *echo.Context) error {
|
||||
u := &user{
|
||||
ID: seq,
|
||||
}
|
||||
if he := c.Bind(u); he != nil {
|
||||
return he
|
||||
if err := c.Bind(u); err != nil {
|
||||
return err
|
||||
}
|
||||
users[u.ID] = u
|
||||
seq++
|
||||
return c.JSON(http.StatusCreated, u)
|
||||
}
|
||||
|
||||
func getUser(c *echo.Context) *echo.HTTPError {
|
||||
func getUser(c *echo.Context) error {
|
||||
id, _ := strconv.Atoi(c.Param("id"))
|
||||
return c.JSON(http.StatusOK, users[id])
|
||||
}
|
||||
|
||||
func updateUser(c *echo.Context) *echo.HTTPError {
|
||||
func updateUser(c *echo.Context) error {
|
||||
u := new(user)
|
||||
if he := c.Bind(u); he != nil {
|
||||
return he
|
||||
if err := c.Bind(u); err != nil {
|
||||
return err
|
||||
}
|
||||
id, _ := strconv.Atoi(c.Param("id"))
|
||||
users[id].Name = u.Name
|
||||
return c.JSON(http.StatusOK, users[id])
|
||||
}
|
||||
|
||||
func deleteUser(c *echo.Context) *echo.HTTPError {
|
||||
func deleteUser(c *echo.Context) error {
|
||||
id, _ := strconv.Atoi(c.Param("id"))
|
||||
delete(users, id)
|
||||
return c.NoContent(http.StatusNoContent)
|
||||
@ -218,22 +218,19 @@ var (
|
||||
)
|
||||
|
||||
// Render HTML
|
||||
func (t *Template) Render(w io.Writer, name string, data interface{}) *echo.HTTPError {
|
||||
if err := t.templates.ExecuteTemplate(w, name, data); err != nil {
|
||||
return &echo.HTTPError{Error: err}
|
||||
}
|
||||
return nil
|
||||
func (t *Template) Render(w io.Writer, name string, data interface{}) error {
|
||||
return t.templates.ExecuteTemplate(w, name, data)
|
||||
}
|
||||
|
||||
//----------
|
||||
// Handlers
|
||||
//----------
|
||||
|
||||
func welcome(c *echo.Context) *echo.HTTPError {
|
||||
func welcome(c *echo.Context) error {
|
||||
return c.Render(http.StatusOK, "welcome", "Joe")
|
||||
}
|
||||
|
||||
func createUser(c *echo.Context) *echo.HTTPError {
|
||||
func createUser(c *echo.Context) error {
|
||||
u := new(user)
|
||||
if err := c.Bind(u); err != nil {
|
||||
return err
|
||||
@ -242,11 +239,11 @@ func createUser(c *echo.Context) *echo.HTTPError {
|
||||
return c.JSON(http.StatusCreated, u)
|
||||
}
|
||||
|
||||
func getUsers(c *echo.Context) *echo.HTTPError {
|
||||
func getUsers(c *echo.Context) error {
|
||||
return c.JSON(http.StatusOK, users)
|
||||
}
|
||||
|
||||
func getUser(c *echo.Context) *echo.HTTPError {
|
||||
func getUser(c *echo.Context) error {
|
||||
return c.JSON(http.StatusOK, users[c.P(0)])
|
||||
}
|
||||
|
||||
@ -268,7 +265,7 @@ func main() {
|
||||
s := stats.New()
|
||||
e.Use(s.Handler)
|
||||
// Route
|
||||
e.Get("/stats", func(c *echo.Context) *echo.HTTPError {
|
||||
e.Get("/stats", func(c *echo.Context) error {
|
||||
return c.JSON(http.StatusOK, s.Data())
|
||||
})
|
||||
|
||||
@ -297,7 +294,7 @@ func main() {
|
||||
// Cached templates
|
||||
templates: template.Must(template.ParseFiles("public/views/welcome.html")),
|
||||
}
|
||||
e.Renderer(t)
|
||||
e.SetRenderer(t)
|
||||
e.Get("/welcome", welcome)
|
||||
|
||||
//-------
|
||||
@ -306,20 +303,20 @@ func main() {
|
||||
|
||||
// Group with parent middleware
|
||||
a := e.Group("/admin")
|
||||
a.Use(func(c *echo.Context) *echo.HTTPError {
|
||||
a.Use(func(c *echo.Context) error {
|
||||
// Security middleware
|
||||
return nil
|
||||
})
|
||||
a.Get("", func(c *echo.Context) *echo.HTTPError {
|
||||
a.Get("", func(c *echo.Context) error {
|
||||
return c.String(http.StatusOK, "Welcome admin!")
|
||||
})
|
||||
|
||||
// Group with no parent middleware
|
||||
g := e.Group("/files", func(c *echo.Context) *echo.HTTPError {
|
||||
g := e.Group("/files", func(c *echo.Context) error {
|
||||
// Security middleware
|
||||
return nil
|
||||
})
|
||||
g.Get("", func(c *echo.Context) *echo.HTTPError {
|
||||
g.Get("", func(c *echo.Context) error {
|
||||
return c.String(http.StatusOK, "Your files!")
|
||||
})
|
||||
|
||||
@ -350,7 +347,7 @@ import (
|
||||
)
|
||||
|
||||
// Handler
|
||||
func hello(c *echo.Context) *echo.HTTPError {
|
||||
func hello(c *echo.Context) error {
|
||||
return c.String(http.StatusOK, "Hello, World!\n")
|
||||
}
|
||||
|
||||
@ -359,7 +356,7 @@ func main() {
|
||||
e := echo.New()
|
||||
|
||||
// Debug mode
|
||||
e.Debug(true)
|
||||
e.SetDebug(true)
|
||||
|
||||
//------------
|
||||
// Middleware
|
||||
|
38
context.go
38
context.go
@ -3,6 +3,8 @@ package echo
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"golang.org/x/net/websocket"
|
||||
)
|
||||
|
||||
type (
|
||||
@ -11,6 +13,7 @@ type (
|
||||
Context struct {
|
||||
Request *http.Request
|
||||
Response *Response
|
||||
Socket *websocket.Conn
|
||||
pnames []string
|
||||
pvalues []string
|
||||
store store
|
||||
@ -53,15 +56,15 @@ func (c *Context) Param(name string) (value string) {
|
||||
|
||||
// Bind binds the request body into specified type v. Default binder does it
|
||||
// based on Content-Type header.
|
||||
func (c *Context) Bind(i interface{}) *HTTPError {
|
||||
func (c *Context) Bind(i interface{}) error {
|
||||
return c.echo.binder(c.Request, i)
|
||||
}
|
||||
|
||||
// Render invokes the registered HTML template renderer and sends a text/html
|
||||
// response with status code.
|
||||
func (c *Context) Render(code int, name string, data interface{}) *HTTPError {
|
||||
func (c *Context) Render(code int, name string, data interface{}) error {
|
||||
if c.echo.renderer == nil {
|
||||
return &HTTPError{Error: RendererNotRegistered}
|
||||
return RendererNotRegistered
|
||||
}
|
||||
c.Response.Header().Set(ContentType, TextHTML+"; charset=utf-8")
|
||||
c.Response.WriteHeader(code)
|
||||
@ -69,44 +72,37 @@ func (c *Context) Render(code int, name string, data interface{}) *HTTPError {
|
||||
}
|
||||
|
||||
// JSON sends an application/json response with status code.
|
||||
func (c *Context) JSON(code int, i interface{}) *HTTPError {
|
||||
func (c *Context) JSON(code int, i interface{}) error {
|
||||
c.Response.Header().Set(ContentType, ApplicationJSON+"; charset=utf-8")
|
||||
c.Response.WriteHeader(code)
|
||||
if err := json.NewEncoder(c.Response).Encode(i); err != nil {
|
||||
return &HTTPError{Error: err}
|
||||
}
|
||||
return nil
|
||||
return json.NewEncoder(c.Response).Encode(i)
|
||||
}
|
||||
|
||||
// String sends a text/plain response with status code.
|
||||
func (c *Context) String(code int, s string) *HTTPError {
|
||||
func (c *Context) String(code int, s string) error {
|
||||
c.Response.Header().Set(ContentType, TextPlain+"; charset=utf-8")
|
||||
c.Response.WriteHeader(code)
|
||||
if _, err := c.Response.Write([]byte(s)); err != nil {
|
||||
return &HTTPError{Error: err}
|
||||
}
|
||||
return nil
|
||||
_, err := c.Response.Write([]byte(s))
|
||||
return err
|
||||
}
|
||||
|
||||
// HTML sends a text/html response with status code.
|
||||
func (c *Context) HTML(code int, html string) *HTTPError {
|
||||
func (c *Context) HTML(code int, html string) error {
|
||||
c.Response.Header().Set(ContentType, TextHTML+"; charset=utf-8")
|
||||
c.Response.WriteHeader(code)
|
||||
if _, err := c.Response.Write([]byte(html)); err != nil {
|
||||
return &HTTPError{Error: err}
|
||||
}
|
||||
return nil
|
||||
_, err := c.Response.Write([]byte(html))
|
||||
return err
|
||||
}
|
||||
|
||||
// NoContent sends a response with no body and a status code.
|
||||
func (c *Context) NoContent(code int) *HTTPError {
|
||||
func (c *Context) NoContent(code int) error {
|
||||
c.Response.WriteHeader(code)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Error invokes the registered HTTP error handler.
|
||||
func (c *Context) Error(he *HTTPError) {
|
||||
c.echo.httpErrorHandler(he, c)
|
||||
func (c *Context) Error(err error) {
|
||||
c.echo.httpErrorHandler(err, c)
|
||||
}
|
||||
|
||||
// Get retrieves data from the context.
|
||||
|
@ -16,17 +16,14 @@ type (
|
||||
}
|
||||
)
|
||||
|
||||
func (t *Template) Render(w io.Writer, name string, data interface{}) *HTTPError {
|
||||
if err := t.templates.ExecuteTemplate(w, name, data); err != nil {
|
||||
return &HTTPError{Error: err}
|
||||
}
|
||||
return nil
|
||||
func (t *Template) Render(w io.Writer, name string, data interface{}) error {
|
||||
return t.templates.ExecuteTemplate(w, name, data)
|
||||
}
|
||||
|
||||
func TestContext(t *testing.T) {
|
||||
b, _ := json.Marshal(u1)
|
||||
r, _ := http.NewRequest(POST, "/users/1", bytes.NewReader(b))
|
||||
c := NewContext(r, &Response{Writer: httptest.NewRecorder()}, New())
|
||||
c := NewContext(r, NewResponse(httptest.NewRecorder()), New())
|
||||
|
||||
//------
|
||||
// Bind
|
||||
|
96
echo.go
96
echo.go
@ -14,6 +14,7 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/mattn/go-colorable"
|
||||
"golang.org/x/net/websocket"
|
||||
)
|
||||
|
||||
type (
|
||||
@ -33,24 +34,23 @@ type (
|
||||
HTTPError struct {
|
||||
Code int
|
||||
Message string
|
||||
Error error
|
||||
}
|
||||
Middleware interface{}
|
||||
MiddlewareFunc func(HandlerFunc) HandlerFunc
|
||||
Handler interface{}
|
||||
HandlerFunc func(*Context) *HTTPError
|
||||
HandlerFunc func(*Context) error
|
||||
|
||||
// HTTPErrorHandler is a centralized HTTP error handler.
|
||||
HTTPErrorHandler func(*HTTPError, *Context)
|
||||
HTTPErrorHandler func(error, *Context)
|
||||
|
||||
BindFunc func(*http.Request, interface{}) *HTTPError
|
||||
BindFunc func(*http.Request, interface{}) error
|
||||
|
||||
// Renderer is the interface that wraps the Render method.
|
||||
//
|
||||
// Render renders the HTML template with given name and specified data.
|
||||
// It writes the output to w.
|
||||
Renderer interface {
|
||||
Render(w io.Writer, name string, data interface{}) *HTTPError
|
||||
Render(w io.Writer, name string, data interface{}) error
|
||||
}
|
||||
)
|
||||
|
||||
@ -120,6 +120,18 @@ var (
|
||||
RendererNotRegistered = errors.New("echo ⇒ renderer not registered")
|
||||
)
|
||||
|
||||
func NewHTTPError(code int, msgs ...string) *HTTPError {
|
||||
he := &HTTPError{Code: code}
|
||||
if len(msgs) == 0 {
|
||||
he.Message = http.StatusText(code)
|
||||
}
|
||||
return he
|
||||
}
|
||||
|
||||
func (e *HTTPError) Error() string {
|
||||
return e.Message
|
||||
}
|
||||
|
||||
// New creates an Echo instance.
|
||||
func New() (e *Echo) {
|
||||
e = &Echo{
|
||||
@ -135,22 +147,22 @@ func New() (e *Echo) {
|
||||
//----------
|
||||
|
||||
e.SetMaxParam(5)
|
||||
e.notFoundHandler = func(c *Context) *HTTPError {
|
||||
return &HTTPError{Code: http.StatusNotFound}
|
||||
e.notFoundHandler = func(c *Context) error {
|
||||
return NewHTTPError(http.StatusNotFound)
|
||||
}
|
||||
e.SetHTTPErrorHandler(func(he *HTTPError, c *Context) {
|
||||
if he.Code == 0 {
|
||||
he.Code = http.StatusInternalServerError
|
||||
e.SetHTTPErrorHandler(func(err error, c *Context) {
|
||||
code := http.StatusInternalServerError
|
||||
msg := http.StatusText(code)
|
||||
if he, ok := err.(*HTTPError); ok {
|
||||
code = he.Code
|
||||
msg = he.Message
|
||||
}
|
||||
if he.Message == "" {
|
||||
he.Message = http.StatusText(he.Code)
|
||||
if e.Debug() {
|
||||
msg = err.Error()
|
||||
}
|
||||
if e.debug && he.Error != nil {
|
||||
he.Message = he.Error.Error()
|
||||
}
|
||||
http.Error(c.Response, he.Message, he.Code)
|
||||
http.Error(c.Response, msg, code)
|
||||
})
|
||||
e.SetBinder(func(r *http.Request, v interface{}) *HTTPError {
|
||||
e.SetBinder(func(r *http.Request, v interface{}) error {
|
||||
ct := r.Header.Get(ContentType)
|
||||
err := UnsupportedMediaType
|
||||
if strings.HasPrefix(ct, ApplicationJSON) {
|
||||
@ -158,10 +170,7 @@ func New() (e *Echo) {
|
||||
} else if strings.HasPrefix(ct, ApplicationForm) {
|
||||
err = nil
|
||||
}
|
||||
if err != nil {
|
||||
return &HTTPError{Error: err}
|
||||
}
|
||||
return nil
|
||||
return err
|
||||
})
|
||||
return
|
||||
}
|
||||
@ -261,6 +270,21 @@ func (e *Echo) Trace(path string, h Handler) {
|
||||
e.add(TRACE, path, h)
|
||||
}
|
||||
|
||||
// WebSocket adds a WebSocket route > handler to the router.
|
||||
func (e *Echo) WebSocket(path string, h HandlerFunc) {
|
||||
e.Get(path, func(c *Context) *HTTPError {
|
||||
wss := websocket.Server{
|
||||
Handler: func(ws *websocket.Conn) {
|
||||
c.Socket = ws
|
||||
c.Response.status = http.StatusSwitchingProtocols
|
||||
h(c)
|
||||
},
|
||||
}
|
||||
wss.ServeHTTP(c.Response.writer, c.Request)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (e *Echo) add(method, path string, h Handler) {
|
||||
key := runtime.FuncForPC(reflect.ValueOf(h).Pointer()).Name()
|
||||
e.uris[key] = path
|
||||
@ -280,7 +304,7 @@ func (e *Echo) Favicon(file string) {
|
||||
// Static serves static files.
|
||||
func (e *Echo) Static(path, root string) {
|
||||
fs := http.StripPrefix(path, http.FileServer(http.Dir(root)))
|
||||
e.Get(path+"*", func(c *Context) *HTTPError {
|
||||
e.Get(path+"*", func(c *Context) error {
|
||||
fs.ServeHTTP(c.Response, c.Request)
|
||||
return nil
|
||||
})
|
||||
@ -288,7 +312,7 @@ func (e *Echo) Static(path, root string) {
|
||||
|
||||
// ServeFile serves a file.
|
||||
func (e *Echo) ServeFile(path, file string) {
|
||||
e.Get(path, func(c *Context) *HTTPError {
|
||||
e.Get(path, func(c *Context) error {
|
||||
http.ServeFile(c.Response, c.Request, file)
|
||||
return nil
|
||||
})
|
||||
@ -376,16 +400,16 @@ func wrapMiddleware(m Middleware) MiddlewareFunc {
|
||||
return m
|
||||
case HandlerFunc:
|
||||
return wrapHandlerFuncMW(m)
|
||||
case func(*Context) *HTTPError:
|
||||
case func(*Context) error:
|
||||
return wrapHandlerFuncMW(m)
|
||||
case func(http.Handler) http.Handler:
|
||||
return func(h HandlerFunc) HandlerFunc {
|
||||
return func(c *Context) (he *HTTPError) {
|
||||
return func(c *Context) (err error) {
|
||||
m(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
c.Response.Writer = w
|
||||
c.Response.writer = w
|
||||
c.Request = r
|
||||
he = h(c)
|
||||
})).ServeHTTP(c.Response.Writer, c.Request)
|
||||
err = h(c)
|
||||
})).ServeHTTP(c.Response.writer, c.Request)
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -403,9 +427,9 @@ func wrapMiddleware(m Middleware) MiddlewareFunc {
|
||||
// Wraps HandlerFunc middleware
|
||||
func wrapHandlerFuncMW(m HandlerFunc) MiddlewareFunc {
|
||||
return func(h HandlerFunc) HandlerFunc {
|
||||
return func(c *Context) *HTTPError {
|
||||
if he := m(c); he != nil {
|
||||
return he
|
||||
return func(c *Context) error {
|
||||
if err := m(c); err != nil {
|
||||
return err
|
||||
}
|
||||
return h(c)
|
||||
}
|
||||
@ -415,9 +439,9 @@ func wrapHandlerFuncMW(m HandlerFunc) MiddlewareFunc {
|
||||
// Wraps http.HandlerFunc middleware
|
||||
func wrapHTTPHandlerFuncMW(m http.HandlerFunc) MiddlewareFunc {
|
||||
return func(h HandlerFunc) HandlerFunc {
|
||||
return func(c *Context) *HTTPError {
|
||||
return func(c *Context) error {
|
||||
if !c.Response.committed {
|
||||
m.ServeHTTP(c.Response.Writer, c.Request)
|
||||
m.ServeHTTP(c.Response.writer, c.Request)
|
||||
}
|
||||
return h(c)
|
||||
}
|
||||
@ -429,15 +453,15 @@ func wrapHandler(h Handler) HandlerFunc {
|
||||
switch h := h.(type) {
|
||||
case HandlerFunc:
|
||||
return h
|
||||
case func(*Context) *HTTPError:
|
||||
case func(*Context) error:
|
||||
return h
|
||||
case http.Handler, http.HandlerFunc:
|
||||
return func(c *Context) *HTTPError {
|
||||
return func(c *Context) error {
|
||||
h.(http.Handler).ServeHTTP(c.Response, c.Request)
|
||||
return nil
|
||||
}
|
||||
case func(http.ResponseWriter, *http.Request):
|
||||
return func(c *Context) *HTTPError {
|
||||
return func(c *Context) error {
|
||||
h(c.Response, c.Request)
|
||||
return nil
|
||||
}
|
||||
|
38
echo_test.go
38
echo_test.go
@ -67,7 +67,7 @@ func TestEchoMiddleware(t *testing.T) {
|
||||
|
||||
// MiddlewareFunc
|
||||
e.Use(MiddlewareFunc(func(h HandlerFunc) HandlerFunc {
|
||||
return func(c *Context) *HTTPError {
|
||||
return func(c *Context) error {
|
||||
b.WriteString("a")
|
||||
return h(c)
|
||||
}
|
||||
@ -75,14 +75,14 @@ func TestEchoMiddleware(t *testing.T) {
|
||||
|
||||
// func(echo.HandlerFunc) echo.HandlerFunc
|
||||
e.Use(func(h HandlerFunc) HandlerFunc {
|
||||
return func(c *Context) *HTTPError {
|
||||
return func(c *Context) error {
|
||||
b.WriteString("b")
|
||||
return h(c)
|
||||
}
|
||||
})
|
||||
|
||||
// func(*echo.Context) *HTTPError
|
||||
e.Use(func(c *Context) *HTTPError {
|
||||
// func(*echo.Context) error
|
||||
e.Use(func(c *Context) error {
|
||||
b.WriteString("c")
|
||||
return nil
|
||||
})
|
||||
@ -111,7 +111,7 @@ func TestEchoMiddleware(t *testing.T) {
|
||||
})
|
||||
|
||||
// Route
|
||||
e.Get("/hello", func(c *Context) *HTTPError {
|
||||
e.Get("/hello", func(c *Context) error {
|
||||
return c.String(http.StatusOK, "world")
|
||||
})
|
||||
|
||||
@ -130,7 +130,7 @@ func TestEchoHandler(t *testing.T) {
|
||||
e := New()
|
||||
|
||||
// HandlerFunc
|
||||
e.Get("/1", HandlerFunc(func(c *Context) *HTTPError {
|
||||
e.Get("/1", HandlerFunc(func(c *Context) error {
|
||||
return c.String(http.StatusOK, "1")
|
||||
}))
|
||||
w := httptest.NewRecorder()
|
||||
@ -140,8 +140,8 @@ func TestEchoHandler(t *testing.T) {
|
||||
t.Error("body should be 1")
|
||||
}
|
||||
|
||||
// func(*echo.Context) *HTTPError
|
||||
e.Get("/2", func(c *Context) *HTTPError {
|
||||
// func(*echo.Context) error
|
||||
e.Get("/2", func(c *Context) error {
|
||||
return c.String(http.StatusOK, "2")
|
||||
})
|
||||
w = httptest.NewRecorder()
|
||||
@ -177,11 +177,11 @@ func TestEchoHandler(t *testing.T) {
|
||||
func TestEchoGroup(t *testing.T) {
|
||||
b := new(bytes.Buffer)
|
||||
e := New()
|
||||
e.Use(func(*Context) *HTTPError {
|
||||
e.Use(func(*Context) error {
|
||||
b.WriteString("1")
|
||||
return nil
|
||||
})
|
||||
e.Get("/users", func(*Context) *HTTPError { return nil })
|
||||
e.Get("/users", func(*Context) error { return nil })
|
||||
w := httptest.NewRecorder()
|
||||
r, _ := http.NewRequest(GET, "/users", nil)
|
||||
e.ServeHTTP(w, r)
|
||||
@ -191,11 +191,11 @@ func TestEchoGroup(t *testing.T) {
|
||||
|
||||
// Group
|
||||
g1 := e.Group("/group1")
|
||||
g1.Use(func(*Context) *HTTPError {
|
||||
g1.Use(func(*Context) error {
|
||||
b.WriteString("2")
|
||||
return nil
|
||||
})
|
||||
g1.Get("/home", func(*Context) *HTTPError { return nil })
|
||||
g1.Get("/home", func(*Context) error { return nil })
|
||||
b.Reset()
|
||||
w = httptest.NewRecorder()
|
||||
r, _ = http.NewRequest(GET, "/group1/home", nil)
|
||||
@ -205,11 +205,11 @@ func TestEchoGroup(t *testing.T) {
|
||||
}
|
||||
|
||||
// Group with no parent middleware
|
||||
g2 := e.Group("/group2", func(*Context) *HTTPError {
|
||||
g2 := e.Group("/group2", func(*Context) error {
|
||||
b.WriteString("3")
|
||||
return nil
|
||||
})
|
||||
g2.Get("/home", func(*Context) *HTTPError { return nil })
|
||||
g2.Get("/home", func(*Context) error { return nil })
|
||||
b.Reset()
|
||||
w = httptest.NewRecorder()
|
||||
r, _ = http.NewRequest(GET, "/group2/home", nil)
|
||||
@ -221,7 +221,7 @@ func TestEchoGroup(t *testing.T) {
|
||||
// Nested group
|
||||
g3 := e.Group("/group3")
|
||||
g4 := g3.Group("/group4")
|
||||
g4.Get("/home", func(c *Context) *HTTPError {
|
||||
g4.Get("/home", func(c *Context) error {
|
||||
return c.NoContent(http.StatusOK)
|
||||
})
|
||||
w = httptest.NewRecorder()
|
||||
@ -234,7 +234,7 @@ func TestEchoGroup(t *testing.T) {
|
||||
|
||||
func TestEchoMethod(t *testing.T) {
|
||||
e := New()
|
||||
h := func(*Context) *HTTPError { return nil }
|
||||
h := func(*Context) error { return nil }
|
||||
e.Connect("/", h)
|
||||
e.Delete("/", h)
|
||||
e.Get("/", h)
|
||||
@ -248,9 +248,9 @@ func TestEchoMethod(t *testing.T) {
|
||||
|
||||
func TestEchoURL(t *testing.T) {
|
||||
e := New()
|
||||
static := func(*Context) *HTTPError { return nil }
|
||||
getUser := func(*Context) *HTTPError { return nil }
|
||||
getFile := func(*Context) *HTTPError { return nil }
|
||||
static := func(*Context) error { return nil }
|
||||
getUser := func(*Context) error { return nil }
|
||||
getFile := func(*Context) error { return nil }
|
||||
e.Get("/static/file", static)
|
||||
e.Get("/users/:id", getUser)
|
||||
e.Get("/users/:uid/files/:fid", getFile)
|
||||
|
@ -24,34 +24,34 @@ var (
|
||||
// Handlers
|
||||
//----------
|
||||
|
||||
func createUser(c *echo.Context) *echo.HTTPError {
|
||||
func createUser(c *echo.Context) error {
|
||||
u := &user{
|
||||
ID: seq,
|
||||
}
|
||||
if he := c.Bind(u); he != nil {
|
||||
return he
|
||||
if err := c.Bind(u); err != nil {
|
||||
return err
|
||||
}
|
||||
users[u.ID] = u
|
||||
seq++
|
||||
return c.JSON(http.StatusCreated, u)
|
||||
}
|
||||
|
||||
func getUser(c *echo.Context) *echo.HTTPError {
|
||||
func getUser(c *echo.Context) error {
|
||||
id, _ := strconv.Atoi(c.Param("id"))
|
||||
return c.JSON(http.StatusOK, users[id])
|
||||
}
|
||||
|
||||
func updateUser(c *echo.Context) *echo.HTTPError {
|
||||
func updateUser(c *echo.Context) error {
|
||||
u := new(user)
|
||||
if he := c.Bind(u); he != nil {
|
||||
return he
|
||||
if err := c.Bind(u); err != nil {
|
||||
return err
|
||||
}
|
||||
id, _ := strconv.Atoi(c.Param("id"))
|
||||
users[id].Name = u.Name
|
||||
return c.JSON(http.StatusOK, users[id])
|
||||
}
|
||||
|
||||
func deleteUser(c *echo.Context) *echo.HTTPError {
|
||||
func deleteUser(c *echo.Context) error {
|
||||
id, _ := strconv.Atoi(c.Param("id"))
|
||||
delete(users, id)
|
||||
return c.NoContent(http.StatusNoContent)
|
||||
|
@ -8,7 +8,7 @@ import (
|
||||
)
|
||||
|
||||
// Handler
|
||||
func hello(c *echo.Context) *echo.HTTPError {
|
||||
func hello(c *echo.Context) error {
|
||||
return c.String(http.StatusOK, "Hello, World!\n")
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@ import (
|
||||
)
|
||||
|
||||
// Handler
|
||||
func hello(c *echo.Context) *echo.HTTPError {
|
||||
func hello(c *echo.Context) error {
|
||||
return c.String(http.StatusOK, "Hello, World!\n")
|
||||
}
|
||||
|
||||
|
@ -29,22 +29,19 @@ var (
|
||||
)
|
||||
|
||||
// Render HTML
|
||||
func (t *Template) Render(w io.Writer, name string, data interface{}) *echo.HTTPError {
|
||||
if err := t.templates.ExecuteTemplate(w, name, data); err != nil {
|
||||
return &echo.HTTPError{Error: err}
|
||||
}
|
||||
return nil
|
||||
func (t *Template) Render(w io.Writer, name string, data interface{}) error {
|
||||
return t.templates.ExecuteTemplate(w, name, data)
|
||||
}
|
||||
|
||||
//----------
|
||||
// Handlers
|
||||
//----------
|
||||
|
||||
func welcome(c *echo.Context) *echo.HTTPError {
|
||||
func welcome(c *echo.Context) error {
|
||||
return c.Render(http.StatusOK, "welcome", "Joe")
|
||||
}
|
||||
|
||||
func createUser(c *echo.Context) *echo.HTTPError {
|
||||
func createUser(c *echo.Context) error {
|
||||
u := new(user)
|
||||
if err := c.Bind(u); err != nil {
|
||||
return err
|
||||
@ -53,11 +50,11 @@ func createUser(c *echo.Context) *echo.HTTPError {
|
||||
return c.JSON(http.StatusCreated, u)
|
||||
}
|
||||
|
||||
func getUsers(c *echo.Context) *echo.HTTPError {
|
||||
func getUsers(c *echo.Context) error {
|
||||
return c.JSON(http.StatusOK, users)
|
||||
}
|
||||
|
||||
func getUser(c *echo.Context) *echo.HTTPError {
|
||||
func getUser(c *echo.Context) error {
|
||||
return c.JSON(http.StatusOK, users[c.P(0)])
|
||||
}
|
||||
|
||||
@ -79,7 +76,7 @@ func main() {
|
||||
s := stats.New()
|
||||
e.Use(s.Handler)
|
||||
// Route
|
||||
e.Get("/stats", func(c *echo.Context) *echo.HTTPError {
|
||||
e.Get("/stats", func(c *echo.Context) error {
|
||||
return c.JSON(http.StatusOK, s.Data())
|
||||
})
|
||||
|
||||
@ -117,20 +114,20 @@ func main() {
|
||||
|
||||
// Group with parent middleware
|
||||
a := e.Group("/admin")
|
||||
a.Use(func(c *echo.Context) *echo.HTTPError {
|
||||
a.Use(func(c *echo.Context) error {
|
||||
// Security middleware
|
||||
return nil
|
||||
})
|
||||
a.Get("", func(c *echo.Context) *echo.HTTPError {
|
||||
a.Get("", func(c *echo.Context) error {
|
||||
return c.String(http.StatusOK, "Welcome admin!")
|
||||
})
|
||||
|
||||
// Group with no parent middleware
|
||||
g := e.Group("/files", func(c *echo.Context) *echo.HTTPError {
|
||||
g := e.Group("/files", func(c *echo.Context) error {
|
||||
// Security middleware
|
||||
return nil
|
||||
})
|
||||
g.Get("", func(c *echo.Context) *echo.HTTPError {
|
||||
g.Get("", func(c *echo.Context) error {
|
||||
return c.String(http.StatusOK, "Your files!")
|
||||
})
|
||||
|
||||
|
@ -16,10 +16,10 @@ const (
|
||||
|
||||
// BasicAuth returns an HTTP basic authentication middleware.
|
||||
func BasicAuth(fn AuthFunc) echo.HandlerFunc {
|
||||
return func(c *echo.Context) (he *echo.HTTPError) {
|
||||
return func(c *echo.Context) error {
|
||||
auth := c.Request.Header.Get(echo.Authorization)
|
||||
i := 0
|
||||
he = &echo.HTTPError{Code: http.StatusUnauthorized}
|
||||
he := echo.NewHTTPError(http.StatusUnauthorized)
|
||||
|
||||
for ; i < len(auth); i++ {
|
||||
c := auth[i]
|
||||
@ -33,31 +33,31 @@ func BasicAuth(fn AuthFunc) echo.HandlerFunc {
|
||||
// Ignore case
|
||||
if i == 0 {
|
||||
if c != Basic[i] && c != 'b' {
|
||||
return
|
||||
return he
|
||||
}
|
||||
} else {
|
||||
if c != Basic[i] {
|
||||
return
|
||||
return he
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Extract credentials
|
||||
b, err := base64.StdEncoding.DecodeString(auth[i:])
|
||||
if err != nil {
|
||||
return
|
||||
return he
|
||||
}
|
||||
cred := string(b)
|
||||
for i := 0; i < len(cred); i++ {
|
||||
if cred[i] == ':' {
|
||||
// Verify credentials
|
||||
if !fn(cred[:i], cred[i+1:]) {
|
||||
return
|
||||
return he
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
return he
|
||||
}
|
||||
}
|
||||
|
@ -25,13 +25,13 @@ func Gzip() echo.MiddlewareFunc {
|
||||
scheme := "gzip"
|
||||
|
||||
return func(h echo.HandlerFunc) echo.HandlerFunc {
|
||||
return func(c *echo.Context) *echo.HTTPError {
|
||||
return func(c *echo.Context) error {
|
||||
if strings.Contains(c.Request.Header.Get(echo.AcceptEncoding), scheme) {
|
||||
w := gzip.NewWriter(c.Response.Writer)
|
||||
w := gzip.NewWriter(c.Response.Writer())
|
||||
defer w.Close()
|
||||
gw := gzipWriter{Writer: w, Response: c.Response}
|
||||
c.Response.Header().Set(echo.ContentEncoding, scheme)
|
||||
c.Response = &echo.Response{Writer: gw}
|
||||
c.Response = echo.NewResponse(gw)
|
||||
}
|
||||
return h(c)
|
||||
}
|
||||
|
@ -14,9 +14,9 @@ func TestGzip(t *testing.T) {
|
||||
// Empty Accept-Encoding header
|
||||
req, _ := http.NewRequest(echo.GET, "/", nil)
|
||||
w := httptest.NewRecorder()
|
||||
res := &echo.Response{Writer: w}
|
||||
res := echo.NewResponse(w)
|
||||
c := echo.NewContext(req, res, echo.New())
|
||||
h := func(c *echo.Context) *echo.HTTPError {
|
||||
h := func(c *echo.Context) error {
|
||||
return c.String(http.StatusOK, "test")
|
||||
}
|
||||
Gzip()(h)(c)
|
||||
@ -28,7 +28,7 @@ func TestGzip(t *testing.T) {
|
||||
// Content-Encoding header
|
||||
req.Header.Set(echo.AcceptEncoding, "gzip")
|
||||
w = httptest.NewRecorder()
|
||||
c.Response = &echo.Response{Writer: w}
|
||||
c.Response = echo.NewResponse(w)
|
||||
Gzip()(h)(c)
|
||||
ce := w.Header().Get(echo.ContentEncoding)
|
||||
if ce != "gzip" {
|
||||
|
@ -10,10 +10,10 @@ import (
|
||||
|
||||
func Logger() echo.MiddlewareFunc {
|
||||
return func(h echo.HandlerFunc) echo.HandlerFunc {
|
||||
return func(c *echo.Context) *echo.HTTPError {
|
||||
return func(c *echo.Context) error {
|
||||
start := time.Now()
|
||||
if he := h(c); he != nil {
|
||||
c.Error(he)
|
||||
if err := h(c); err != nil {
|
||||
c.Error(err)
|
||||
}
|
||||
end := time.Now()
|
||||
method := c.Request.Method
|
||||
|
@ -1 +1,36 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"github.com/labstack/echo"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestLogger(t *testing.T) {
|
||||
e := echo.New()
|
||||
req, _ := http.NewRequest(echo.GET, "/", nil)
|
||||
w := httptest.NewRecorder()
|
||||
res := echo.NewResponse(w)
|
||||
c := echo.NewContext(req, res, e)
|
||||
|
||||
// Status 2xx
|
||||
h := func(c *echo.Context) error {
|
||||
return c.String(http.StatusOK, "test")
|
||||
}
|
||||
Logger()(h)(c)
|
||||
|
||||
// Status 4xx
|
||||
c.Response = echo.NewResponse(w)
|
||||
h = func(c *echo.Context) error {
|
||||
return c.String(http.StatusNotFound, "test")
|
||||
}
|
||||
Logger()(h)(c)
|
||||
|
||||
// Status 5xx
|
||||
c.Response = echo.NewResponse(w)
|
||||
h = func(c *echo.Context) error {
|
||||
return c.String(http.StatusInternalServerError, "test")
|
||||
}
|
||||
Logger()(h)(c)
|
||||
}
|
||||
|
@ -13,15 +13,13 @@ import (
|
||||
func Recover() echo.MiddlewareFunc {
|
||||
// TODO: Provide better stack trace `https://github.com/go-errors/errors` `https://github.com/docker/libcontainer/tree/master/stacktrace`
|
||||
return func(h echo.HandlerFunc) echo.HandlerFunc {
|
||||
return func(c *echo.Context) *echo.HTTPError {
|
||||
return func(c *echo.Context) error {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
trace := make([]byte, 1<<16)
|
||||
n := runtime.Stack(trace, true)
|
||||
c.Error(&echo.HTTPError{
|
||||
Error: fmt.Errorf("echo => panic recover\n %v\n stack trace %d bytes\n %s",
|
||||
err, n, trace[:n]),
|
||||
})
|
||||
c.Error(fmt.Errorf("echo => panic recover\n %v\n stack trace %d bytes\n %s",
|
||||
err, n, trace[:n]))
|
||||
}
|
||||
}()
|
||||
return h(c)
|
||||
|
@ -13,9 +13,9 @@ func TestRecover(t *testing.T) {
|
||||
e.SetDebug(true)
|
||||
req, _ := http.NewRequest(echo.GET, "/", nil)
|
||||
w := httptest.NewRecorder()
|
||||
res := &echo.Response{Writer: w}
|
||||
res := echo.NewResponse(w)
|
||||
c := echo.NewContext(req, res, e)
|
||||
h := func(c *echo.Context) *echo.HTTPError {
|
||||
h := func(c *echo.Context) error {
|
||||
panic("test")
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ type (
|
||||
// StripTrailingSlash returns a middleware which removes trailing slash from request
|
||||
// path.
|
||||
func StripTrailingSlash() echo.HandlerFunc {
|
||||
return func(c *echo.Context) *echo.HTTPError {
|
||||
return func(c *echo.Context) error {
|
||||
p := c.Request.URL.Path
|
||||
l := len(p)
|
||||
if p[l-1] == '/' {
|
||||
@ -35,7 +35,7 @@ func RedirectToSlash(opts ...RedirectToSlashOptions) echo.HandlerFunc {
|
||||
}
|
||||
}
|
||||
|
||||
return func(c *echo.Context) (he *echo.HTTPError) {
|
||||
return func(c *echo.Context) error {
|
||||
p := c.Request.URL.Path
|
||||
l := len(p)
|
||||
if p[l-1] != '/' {
|
||||
|
@ -10,7 +10,7 @@ import (
|
||||
|
||||
func TestStripTrailingSlash(t *testing.T) {
|
||||
req, _ := http.NewRequest(echo.GET, "/users/", nil)
|
||||
res := &echo.Response{Writer: httptest.NewRecorder()}
|
||||
res := echo.NewResponse(httptest.NewRecorder())
|
||||
c := echo.NewContext(req, res, echo.New())
|
||||
StripTrailingSlash()(c)
|
||||
p := c.Request.URL.Path
|
||||
@ -21,7 +21,7 @@ func TestStripTrailingSlash(t *testing.T) {
|
||||
|
||||
func TestRedirectToSlash(t *testing.T) {
|
||||
req, _ := http.NewRequest(echo.GET, "/users", nil)
|
||||
res := &echo.Response{Writer: httptest.NewRecorder()}
|
||||
res := echo.NewResponse(httptest.NewRecorder())
|
||||
c := echo.NewContext(req, res, echo.New())
|
||||
RedirectToSlash(RedirectToSlashOptions{Code: http.StatusTemporaryRedirect})(c)
|
||||
|
||||
|
24
response.go
24
response.go
@ -11,15 +11,23 @@ import (
|
||||
|
||||
type (
|
||||
Response struct {
|
||||
Writer http.ResponseWriter
|
||||
writer http.ResponseWriter
|
||||
status int
|
||||
size int64
|
||||
committed bool
|
||||
}
|
||||
)
|
||||
|
||||
func NewResponse(w http.ResponseWriter) *Response {
|
||||
return &Response{writer: w}
|
||||
}
|
||||
|
||||
func (r *Response) Header() http.Header {
|
||||
return r.Writer.Header()
|
||||
return r.writer.Header()
|
||||
}
|
||||
|
||||
func (r *Response) Writer() http.ResponseWriter {
|
||||
return r.writer
|
||||
}
|
||||
|
||||
func (r *Response) WriteHeader(code int) {
|
||||
@ -29,29 +37,29 @@ func (r *Response) WriteHeader(code int) {
|
||||
return
|
||||
}
|
||||
r.status = code
|
||||
r.Writer.WriteHeader(code)
|
||||
r.writer.WriteHeader(code)
|
||||
r.committed = true
|
||||
}
|
||||
|
||||
func (r *Response) Write(b []byte) (n int, err error) {
|
||||
n, err = r.Writer.Write(b)
|
||||
n, err = r.writer.Write(b)
|
||||
r.size += int64(n)
|
||||
return n, err
|
||||
}
|
||||
|
||||
// Flush wraps response writer's Flush function.
|
||||
func (r *Response) Flush() {
|
||||
r.Writer.(http.Flusher).Flush()
|
||||
r.writer.(http.Flusher).Flush()
|
||||
}
|
||||
|
||||
// Hijack wraps response writer's Hijack function.
|
||||
func (r *Response) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||
return r.Writer.(http.Hijacker).Hijack()
|
||||
return r.writer.(http.Hijacker).Hijack()
|
||||
}
|
||||
|
||||
// CloseNotify wraps response writer's CloseNotify function.
|
||||
func (r *Response) CloseNotify() <-chan bool {
|
||||
return r.Writer.(http.CloseNotifier).CloseNotify()
|
||||
return r.writer.(http.CloseNotifier).CloseNotify()
|
||||
}
|
||||
|
||||
func (r *Response) Status() int {
|
||||
@ -63,7 +71,7 @@ func (r *Response) Size() int64 {
|
||||
}
|
||||
|
||||
func (r *Response) reset(w http.ResponseWriter) {
|
||||
r.Writer = w
|
||||
r.writer = w
|
||||
r.status = http.StatusOK
|
||||
r.committed = false
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ import (
|
||||
)
|
||||
|
||||
func TestResponse(t *testing.T) {
|
||||
r := &Response{Writer: httptest.NewRecorder()}
|
||||
r := NewResponse(httptest.NewRecorder())
|
||||
|
||||
// Header
|
||||
if r.Header() == nil {
|
||||
|
@ -283,7 +283,7 @@ func TestRouterStatic(t *testing.T) {
|
||||
r := New().Router
|
||||
b := new(bytes.Buffer)
|
||||
path := "/folders/a/files/echo.gif"
|
||||
r.Add(GET, path, func(*Context) *HTTPError {
|
||||
r.Add(GET, path, func(*Context) error {
|
||||
b.WriteString(path)
|
||||
return nil
|
||||
}, nil)
|
||||
@ -300,7 +300,7 @@ func TestRouterStatic(t *testing.T) {
|
||||
|
||||
func TestRouterParam(t *testing.T) {
|
||||
r := New().Router
|
||||
r.Add(GET, "/users/:id", func(c *Context) *HTTPError {
|
||||
r.Add(GET, "/users/:id", func(c *Context) error {
|
||||
return nil
|
||||
}, nil)
|
||||
h, _ := r.Find(GET, "/users/1", context)
|
||||
@ -315,7 +315,7 @@ func TestRouterParam(t *testing.T) {
|
||||
|
||||
func TestRouterTwoParam(t *testing.T) {
|
||||
r := New().Router
|
||||
r.Add(GET, "/users/:uid/files/:fid", func(*Context) *HTTPError {
|
||||
r.Add(GET, "/users/:uid/files/:fid", func(*Context) error {
|
||||
return nil
|
||||
}, nil)
|
||||
|
||||
@ -339,7 +339,7 @@ func TestRouterTwoParam(t *testing.T) {
|
||||
|
||||
func TestRouterMatchAny(t *testing.T) {
|
||||
r := New().Router
|
||||
r.Add(GET, "/users/*", func(*Context) *HTTPError {
|
||||
r.Add(GET, "/users/*", func(*Context) error {
|
||||
return nil
|
||||
}, nil)
|
||||
|
||||
@ -364,7 +364,7 @@ func TestRouterMatchAny(t *testing.T) {
|
||||
|
||||
func TestRouterMicroParam(t *testing.T) {
|
||||
r := New().Router
|
||||
r.Add(GET, "/:a/:b/:c", func(c *Context) *HTTPError {
|
||||
r.Add(GET, "/:a/:b/:c", func(c *Context) error {
|
||||
return nil
|
||||
}, nil)
|
||||
h, _ := r.Find(GET, "/1/2/3", context)
|
||||
@ -388,11 +388,11 @@ func TestRouterMultiRoute(t *testing.T) {
|
||||
b := new(bytes.Buffer)
|
||||
|
||||
// Routes
|
||||
r.Add(GET, "/users", func(*Context) *HTTPError {
|
||||
r.Add(GET, "/users", func(*Context) error {
|
||||
b.WriteString("/users")
|
||||
return nil
|
||||
}, nil)
|
||||
r.Add(GET, "/users/:id", func(c *Context) *HTTPError {
|
||||
r.Add(GET, "/users/:id", func(c *Context) error {
|
||||
return nil
|
||||
}, nil)
|
||||
|
||||
@ -428,31 +428,31 @@ func TestRouterPriority(t *testing.T) {
|
||||
r := New().Router
|
||||
|
||||
// Routes
|
||||
r.Add(GET, "/users", func(c *Context) *HTTPError {
|
||||
r.Add(GET, "/users", func(c *Context) error {
|
||||
c.Set("a", 1)
|
||||
return nil
|
||||
}, nil)
|
||||
r.Add(GET, "/users/new", func(c *Context) *HTTPError {
|
||||
r.Add(GET, "/users/new", func(c *Context) error {
|
||||
c.Set("b", 2)
|
||||
return nil
|
||||
}, nil)
|
||||
r.Add(GET, "/users/:id", func(c *Context) *HTTPError {
|
||||
r.Add(GET, "/users/:id", func(c *Context) error {
|
||||
c.Set("c", 3)
|
||||
return nil
|
||||
}, nil)
|
||||
r.Add(GET, "/users/dew", func(c *Context) *HTTPError {
|
||||
r.Add(GET, "/users/dew", func(c *Context) error {
|
||||
c.Set("d", 4)
|
||||
return nil
|
||||
}, nil)
|
||||
r.Add(GET, "/users/:id/files", func(c *Context) *HTTPError {
|
||||
r.Add(GET, "/users/:id/files", func(c *Context) error {
|
||||
c.Set("e", 5)
|
||||
return nil
|
||||
}, nil)
|
||||
r.Add(GET, "/users/newsee", func(c *Context) *HTTPError {
|
||||
r.Add(GET, "/users/newsee", func(c *Context) error {
|
||||
c.Set("f", 6)
|
||||
return nil
|
||||
}, nil)
|
||||
r.Add(GET, "/users/*", func(c *Context) *HTTPError {
|
||||
r.Add(GET, "/users/*", func(c *Context) error {
|
||||
c.Set("g", 7)
|
||||
return nil
|
||||
}, nil)
|
||||
@ -540,14 +540,14 @@ func TestRouterParamNames(t *testing.T) {
|
||||
b := new(bytes.Buffer)
|
||||
|
||||
// Routes
|
||||
r.Add(GET, "/users", func(*Context) *HTTPError {
|
||||
r.Add(GET, "/users", func(*Context) error {
|
||||
b.WriteString("/users")
|
||||
return nil
|
||||
}, nil)
|
||||
r.Add(GET, "/users/:id", func(c *Context) *HTTPError {
|
||||
r.Add(GET, "/users/:id", func(c *Context) error {
|
||||
return nil
|
||||
}, nil)
|
||||
r.Add(GET, "/users/:uid/files/:fid", func(c *Context) *HTTPError {
|
||||
r.Add(GET, "/users/:uid/files/:fid", func(c *Context) error {
|
||||
return nil
|
||||
}, nil)
|
||||
|
||||
@ -598,7 +598,7 @@ func TestRouterParamNames(t *testing.T) {
|
||||
func TestRouterAPI(t *testing.T) {
|
||||
r := New().Router
|
||||
for _, route := range api {
|
||||
r.Add(route.method, route.path, func(c *Context) *HTTPError {
|
||||
r.Add(route.method, route.path, func(c *Context) error {
|
||||
for i, n := range c.pnames {
|
||||
if n != "" {
|
||||
if ":"+n != c.P(uint8(i)) {
|
||||
@ -619,7 +619,7 @@ func TestRouterAPI(t *testing.T) {
|
||||
|
||||
func TestRouterServeHTTP(t *testing.T) {
|
||||
r := New().Router
|
||||
r.Add(GET, "/users", func(*Context) *HTTPError {
|
||||
r.Add(GET, "/users", func(*Context) error {
|
||||
return nil
|
||||
}, nil)
|
||||
|
||||
|
@ -41,16 +41,16 @@ for many use cases. Restricting path parameters allows us to use memory efficien
|
||||
|
||||
Registers a custom `Echo.HTTPErrorHandler`.
|
||||
|
||||
Default handler sends `HTTPError.Message` HTTP response with `HTTPError.Code` status
|
||||
code.
|
||||
Default handler rules
|
||||
|
||||
- If HTTPError.Code is not set it uses `500`".
|
||||
- If HTTPError.Message is not set it uses status code text.
|
||||
- If debug mode is enabled, HTTPError.Message is set to `HTTPError.Error.Error()`.
|
||||
- If error is of type `Echo.HTTPError` it sends HTTP response with status code `HTTPError.Code`
|
||||
and message `HTTPError.Message`.
|
||||
- Else it sends `500 - Internal Server Error`.
|
||||
- If debug mode is enabled, it uses `error.Error()` as status message.
|
||||
|
||||
### Debug
|
||||
|
||||
`echo.SetDebug(on bool)`
|
||||
`Echo.SetDebug(on bool)`
|
||||
|
||||
Enables debug mode.
|
||||
|
||||
@ -67,12 +67,12 @@ code below registers a route for method `GET`, path `/hello` and a handler which
|
||||
`Hello!` HTTP response.
|
||||
|
||||
```go
|
||||
echo.Get("/hello", func(*echo.Context) *HTTPError {
|
||||
echo.Get("/hello", func(*echo.Context) error {
|
||||
return c.String(http.StatusOK, "Hello!")
|
||||
})
|
||||
```
|
||||
|
||||
Echo's default handler is `func(*echo.Context) *echo.HTTPError` where `echo.Context`
|
||||
Echo's default handler is `func(*echo.Context) error` where `echo.Context`
|
||||
primarily holds HTTP request and response objects. Echo also has a support for other
|
||||
types of handlers.
|
||||
|
||||
@ -89,7 +89,7 @@ or by index `echo.Context.P(i uint8) string`. Getting parameter by index gives a
|
||||
slightly better performance.
|
||||
|
||||
```go
|
||||
echo.Get("/users/:id", func(c *echo.Context) *HTTPError {
|
||||
echo.Get("/users/:id", func(c *echo.Context) error {
|
||||
// By name
|
||||
id := c.Param("id")
|
||||
|
||||
@ -119,15 +119,15 @@ match
|
||||
#### Example
|
||||
|
||||
```go
|
||||
e.Get("/users/:id", func(c *echo.Context) *HTTPError {
|
||||
e.Get("/users/:id", func(c *echo.Context) error {
|
||||
return c.String(http.StatusOK, "/users/:id")
|
||||
})
|
||||
|
||||
e.Get("/users/new", func(c *echo.Context) *HTTPError {
|
||||
e.Get("/users/new", func(c *echo.Context) error {
|
||||
return c.String(http.StatusOK, "/users/new")
|
||||
})
|
||||
|
||||
e.Get("/users/1/files/*", func(c *echo.Context) *HTTPError {
|
||||
e.Get("/users/1/files/*", func(c *echo.Context) error {
|
||||
return c.String(http.StatusOK, "/users/1/files/*")
|
||||
})
|
||||
```
|
||||
@ -152,7 +152,7 @@ application.
|
||||
|
||||
```go
|
||||
// Handler
|
||||
h := func(*echo.Context) *HTTPError {
|
||||
h := func(*echo.Context) error {
|
||||
return c.String(http.StatusOK, "OK")
|
||||
}
|
||||
|
||||
@ -169,7 +169,7 @@ e.Get("/users/:id", h)
|
||||
### JSON
|
||||
|
||||
```go
|
||||
context.JSON(code int, v interface{}) *HTTPError
|
||||
context.JSON(code int, v interface{}) error
|
||||
```
|
||||
|
||||
Sends a JSON HTTP response with status code.
|
||||
@ -177,7 +177,7 @@ Sends a JSON HTTP response with status code.
|
||||
### String
|
||||
|
||||
```go
|
||||
context.String(code int, s string) *HTTPError
|
||||
context.String(code int, s string) error
|
||||
```
|
||||
|
||||
Sends a text/plain HTTP response with status code.
|
||||
@ -185,7 +185,7 @@ Sends a text/plain HTTP response with status code.
|
||||
### HTML
|
||||
|
||||
```go
|
||||
func (c *Context) HTML(code int, html string) *HTTPError
|
||||
func (c *Context) HTML(code int, html string) error
|
||||
```
|
||||
|
||||
Sends an HTML HTTP response with status code.
|
||||
@ -228,8 +228,8 @@ e.Favicon("public/favicon.ico")
|
||||
|
||||
## Error Handling
|
||||
|
||||
Echo advocates centralized HTTP error handling by returning `*echo.HTTPError` from
|
||||
middleware and handlers.
|
||||
Echo advocates centralized HTTP error handling by returning `error` from middleware
|
||||
and handlers.
|
||||
|
||||
It allows you to
|
||||
|
||||
@ -237,8 +237,8 @@ It allows you to
|
||||
- Customize HTTP responses.
|
||||
- Recover from panics inside middleware or handlers.
|
||||
|
||||
For example, when a basic auth middleware finds invalid credentials it returns 401
|
||||
"Unauthorized" error, aborting the current HTTP request.
|
||||
For example, when a basic auth middleware finds invalid credentials it returns
|
||||
`401 - Unauthorized` error, aborting the current HTTP request.
|
||||
|
||||
```go
|
||||
package main
|
||||
@ -251,18 +251,18 @@ import (
|
||||
|
||||
func main() {
|
||||
e := echo.New()
|
||||
e.Use(func(c *echo.Context) *echo.HTTPError {
|
||||
e.Use(func(c *echo.Context) error {
|
||||
// Extract the credentials from HTTP request header and perform a security
|
||||
// check
|
||||
|
||||
// For invalid credentials
|
||||
return &echo.HTTPError{Code: http.StatusUnauthorized}
|
||||
return echo.NewHTTPError(http.StatusUnauthorized)
|
||||
})
|
||||
e.Get("/welcome", welcome)
|
||||
e.Run(":1323")
|
||||
}
|
||||
|
||||
func welcome(c *echo.Context) *echo.HTTPError {
|
||||
func welcome(c *echo.Context) error {
|
||||
return c.String(http.StatusOK, "Welcome!")
|
||||
}
|
||||
```
|
||||
|
@ -16,14 +16,14 @@ Echo is a fast HTTP router (zero memory allocation) and micro web framework in G
|
||||
- `echo.MiddlewareFunc`
|
||||
- `func(echo.HandlerFunc) echo.HandlerFunc`
|
||||
- `echo.HandlerFunc`
|
||||
- `func(*echo.Context) *echo.HTTPError`
|
||||
- `func(*echo.Context) error`
|
||||
- `func(http.Handler) http.Handler`
|
||||
- `http.Handler`
|
||||
- `http.HandlerFunc`
|
||||
- `func(http.ResponseWriter, *http.Request)`
|
||||
- Handler
|
||||
- `echo.HandlerFunc`
|
||||
- `func(*echo.Context) *echo.HTTPError`
|
||||
- `func(*echo.Context) error`
|
||||
- `http.Handler`
|
||||
- `http.HandlerFunc`
|
||||
- `func(http.ResponseWriter, *http.Request)`
|
||||
@ -57,7 +57,7 @@ import (
|
||||
)
|
||||
|
||||
// Handler
|
||||
func hello(c *echo.Context) *echo.HTTPError {
|
||||
func hello(c *echo.Context) error {
|
||||
return c.String(http.StatusOK, "Hello, World!\n")
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user