diff --git a/README.md b/README.md index f0659451..8f5249ac 100644 --- a/README.md +++ b/README.md @@ -8,21 +8,21 @@ Echo is a fast HTTP router (zero memory allocation) and micro web framework in G - Extensible middleware/handler, supports: - Middleware - `func(*echo.Context)` - - `func(*echo.Context) error` + - `func(*echo.Context) *echo.HTTPError` - `func(echo.HandlerFunc) echo.HandlerFunc` - `func(http.Handler) http.Handler` - `http.Handler` - `http.HandlerFunc` - `func(http.ResponseWriter, *http.Request)` - - `func(http.ResponseWriter, *http.Request) error` + - `func(http.ResponseWriter, *http.Request) *echo.HTTPError` - Handler - `echo.HandlerFunc` - - `func(*echo.Context) error` + - `func(*echo.Context) *echo.HTTPError` - `func(*echo.Context)` - `http.Handler` - `http.HandlerFunc` - `func(http.ResponseWriter, *http.Request)` - - `func(http.ResponseWriter, *http.Request) error` + - `func(http.ResponseWriter, *http.Request) *echo.HTTPError` - Sub routing with groups. - Handy encoding/decoding functions. - Serve static files, including index. @@ -85,8 +85,8 @@ import ( ) // Handler -func hello(c *echo.Context) { - c.String(http.StatusOK, "Hello, World!\n") +func hello(c *echo.Context) *echo.HTTPError { + return c.String(http.StatusOK, "Hello, World!\n") } func main() { diff --git a/context.go b/context.go index 1a8c9bc2..b25dbdb4 100644 --- a/context.go +++ b/context.go @@ -42,15 +42,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(v interface{}) error { +func (c *Context) Bind(v interface{}) *HTTPError { return c.echo.binder(c.Request, v) } // 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{}) error { +func (c *Context) Render(code int, name string, data interface{}) *HTTPError { if c.echo.renderer == nil { - return RendererNotRegistered + return &HTTPError{Error: RendererNotRegistered} } c.Response.Header().Set(HeaderContentType, MIMEHTML+"; charset=utf-8") c.Response.WriteHeader(code) @@ -58,37 +58,44 @@ func (c *Context) Render(code int, name string, data interface{}) error { } // JSON sends an application/json response with status code. -func (c *Context) JSON(code int, v interface{}) error { +func (c *Context) JSON(code int, v interface{}) *HTTPError { c.Response.Header().Set(HeaderContentType, MIMEJSON+"; charset=utf-8") c.Response.WriteHeader(code) - return json.NewEncoder(c.Response).Encode(v) + if err := json.NewEncoder(c.Response).Encode(v); err != nil { + return &HTTPError{Error: err} + } + return nil } // String sends a text/plain response with status code. -func (c *Context) String(code int, s string) error { +func (c *Context) String(code int, s string) *HTTPError { c.Response.Header().Set(HeaderContentType, MIMEText+"; charset=utf-8") c.Response.WriteHeader(code) - _, err := c.Response.Write([]byte(s)) - return err + if _, err := c.Response.Write([]byte(s)); err != nil { + return &HTTPError{Error: err} + } + return nil } // HTML sends a text/html response with status code. -func (c *Context) HTML(code int, html string) error { +func (c *Context) HTML(code int, html string) *HTTPError { c.Response.Header().Set(HeaderContentType, MIMEHTML+"; charset=utf-8") c.Response.WriteHeader(code) - _, err := c.Response.Write([]byte(html)) - return err + if _, err := c.Response.Write([]byte(html)); err != nil { + return &HTTPError{Error: err} + } + return nil } // NoContent sends a response with no body and a status code. -func (c *Context) NoContent(code int) error { +func (c *Context) NoContent(code int) *HTTPError { c.Response.WriteHeader(code) return nil } // Error invokes the registered HTTP error handler. -func (c *Context) Error(code int, err error) { - c.echo.httpErrorHandler(code, err, c) +func (c *Context) Error(he *HTTPError) { + c.echo.httpErrorHandler(he, c) } // Get retrieves data from the context. diff --git a/context_test.go b/context_test.go index 17f5fa23..0ced8ecb 100644 --- a/context_test.go +++ b/context_test.go @@ -16,8 +16,11 @@ type ( } ) -func (t *Template) Render(w io.Writer, name string, data interface{}) error { - return t.templates.ExecuteTemplate(w, name, data) +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 TestContext(t *testing.T) { @@ -38,24 +41,24 @@ func TestContext(t *testing.T) { // JSON r.Header.Set(HeaderContentType, MIMEJSON) u2 := new(user) - if err := c.Bind(u2); err != nil { - t.Error(err) + if he := c.Bind(u2); he != nil { + t.Errorf("bind %#v", he) } verifyUser(u2, t) // FORM r.Header.Set(HeaderContentType, MIMEForm) u2 = new(user) - if err := c.Bind(u2); err != nil { - t.Error(err) + if he := c.Bind(u2); he != nil { + t.Errorf("bind %#v", he) } // TODO: add verification // Unsupported r.Header.Set(HeaderContentType, "") u2 = new(user) - if err := c.Bind(u2); err == nil { - t.Error(err) + if he := c.Bind(u2); he == nil { + t.Errorf("bind %#v", he) } // TODO: add verification @@ -87,33 +90,33 @@ func TestContext(t *testing.T) { templates: template.Must(template.New("hello").Parse("{{.}}")), } c.echo.renderer = tpl - if err := c.Render(http.StatusOK, "hello", "Joe"); err != nil { - t.Errorf("render %v", err) + if he := c.Render(http.StatusOK, "hello", "Joe"); he != nil { + t.Errorf("render %#v", he.Error) } c.echo.renderer = nil - if err := c.Render(http.StatusOK, "hello", "Joe"); err == nil { + if he := c.Render(http.StatusOK, "hello", "Joe"); he.Error == nil { t.Error("render should error out") } // JSON r.Header.Set(HeaderAccept, MIMEJSON) c.Response.committed = false - if err := c.JSON(http.StatusOK, u1); err != nil { - t.Errorf("json %v", err) + if he := c.JSON(http.StatusOK, u1); he != nil { + t.Errorf("json %#v", he) } // String r.Header.Set(HeaderAccept, MIMEText) c.Response.committed = false - if err := c.String(http.StatusOK, "Hello, World!"); err != nil { - t.Errorf("string %v", err) + if he := c.String(http.StatusOK, "Hello, World!"); he != nil { + t.Errorf("string %#v", he.Error) } // HTML r.Header.Set(HeaderAccept, MIMEHTML) c.Response.committed = false - if err := c.HTML(http.StatusOK, "Hello, World!"); err != nil { - t.Errorf("html %v", err) + if he := c.HTML(http.StatusOK, "Hello, World!"); he != nil { + t.Errorf("html %v", he.Error) } // Redirect diff --git a/echo.go b/echo.go index 1c671d61..1484b4af 100644 --- a/echo.go +++ b/echo.go @@ -13,7 +13,6 @@ import ( "strings" "sync" - "github.com/labstack/gommon/color" "github.com/mattn/go-colorable" ) @@ -30,22 +29,27 @@ type ( uris map[Handler]string pool sync.Pool } + HTTPError struct { + Code int + Message string + Error error + } Middleware interface{} MiddlewareFunc func(HandlerFunc) HandlerFunc Handler interface{} - HandlerFunc func(*Context) error + HandlerFunc func(*Context) *HTTPError // HTTPErrorHandler is a centralized HTTP error handler. - HTTPErrorHandler func(int, error, *Context) + HTTPErrorHandler func(*HTTPError, *Context) - BindFunc func(*http.Request, interface{}) error + BindFunc func(*http.Request, interface{}) *HTTPError // 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{}) error + Render(w io.Writer, name string, data interface{}) *HTTPError } ) @@ -125,21 +129,27 @@ func New() (e *Echo) { e.NotFoundHandler(func(c *Context) { http.Error(c.Response, http.StatusText(http.StatusNotFound), http.StatusNotFound) }) - e.HTTPErrorHandler(func(code int, err error, c *Context) { - if err != nil { - // TODO: Warning - log.Printf("echo: %s", color.Yellow("http error handler not registered")) - http.Error(c.Response, err.Error(), code) + e.HTTPErrorHandler(func(he *HTTPError, c *Context) { + if he.Code == 0 { + he.Code = http.StatusInternalServerError } + if he.Message == "" && he.Error != nil { + he.Message = he.Error.Error() + } + http.Error(c.Response, he.Message, he.Code) }) - e.Binder(func(r *http.Request, v interface{}) error { + e.Binder(func(r *http.Request, v interface{}) *HTTPError { ct := r.Header.Get(HeaderContentType) + err := UnsupportedMediaType if strings.HasPrefix(ct, MIMEJSON) { - return json.NewDecoder(r.Body).Decode(v) + err = json.NewDecoder(r.Body).Decode(v) } else if strings.HasPrefix(ct, MIMEForm) { - return nil + err = nil } - return UnsupportedMediaType + if err != nil { + return &HTTPError{Error: err} + } + return nil }) return } @@ -272,7 +282,7 @@ func (e *Echo) add(method, path string, h Handler) { // 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) error { + e.Get(path+"/*", func(c *Context) *HTTPError { fs.ServeHTTP(c.Response, c.Request) return nil }) @@ -280,7 +290,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) error { + e.Get(path, func(c *Context) *HTTPError { http.ServeFile(c.Response, c.Request, file) return nil }) @@ -308,8 +318,8 @@ func (e *Echo) ServeHTTP(w http.ResponseWriter, r *http.Request) { } // Execute chain - if err := h(c); err != nil { - e.httpErrorHandler(http.StatusInternalServerError, err, c) + if he := h(c); he != nil { + e.httpErrorHandler(he, c) } e.pool.Put(c) @@ -342,16 +352,19 @@ func wrapM(m Middleware) MiddlewareFunc { switch m := m.(type) { case func(*Context): return func(h HandlerFunc) HandlerFunc { - return func(c *Context) error { + return func(c *Context) *HTTPError { m(c) - return h(c) + if !c.Response.committed { + h(c) + } + return nil } } - case func(*Context) error: + case func(*Context) *HTTPError: return func(h HandlerFunc) HandlerFunc { - return func(c *Context) error { - if err := m(c); err != nil { - return err + return func(c *Context) *HTTPError { + if he := m(c); he != nil { + return he } return h(c) } @@ -360,36 +373,42 @@ func wrapM(m Middleware) MiddlewareFunc { return m case func(http.Handler) http.Handler: return func(h HandlerFunc) HandlerFunc { - return func(c *Context) (err error) { + return func(c *Context) (he *HTTPError) { m(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { c.Response.Writer = w c.Request = r - err = h(c) + he = h(c) })).ServeHTTP(c.Response.Writer, c.Request) return } } case http.Handler, http.HandlerFunc: return func(h HandlerFunc) HandlerFunc { - return func(c *Context) error { + return func(c *Context) *HTTPError { m.(http.Handler).ServeHTTP(c.Response.Writer, c.Request) return h(c) } } case func(http.ResponseWriter, *http.Request): return func(h HandlerFunc) HandlerFunc { - return func(c *Context) error { - m(c.Response.Writer, c.Request) - return h(c) + return func(c *Context) *HTTPError { + m(c.Response, c.Request) + if !c.Response.committed { + h(c) + } + return nil } } - case func(http.ResponseWriter, *http.Request) error: + case func(http.ResponseWriter, *http.Request) *HTTPError: return func(h HandlerFunc) HandlerFunc { - return func(c *Context) error { - if err := m(c.Response.Writer, c.Request); err != nil { - return err + return func(c *Context) *HTTPError { + if he := m(c.Response, c.Request); he != nil { + return he } - return h(c) + if !c.Response.committed { + h(c) + } + return nil } } default: @@ -402,25 +421,25 @@ func wrapH(h Handler) HandlerFunc { switch h := h.(type) { case HandlerFunc: return h - case func(*Context) error: + case func(*Context) *HTTPError: return h case func(*Context): - return func(c *Context) error { + return func(c *Context) *HTTPError { h(c) return nil } case http.Handler, http.HandlerFunc: - return func(c *Context) error { + return func(c *Context) *HTTPError { h.(http.Handler).ServeHTTP(c.Response, c.Request) return nil } case func(http.ResponseWriter, *http.Request): - return func(c *Context) error { + return func(c *Context) *HTTPError { h(c.Response, c.Request) return nil } - case func(http.ResponseWriter, *http.Request) error: - return func(c *Context) error { + case func(http.ResponseWriter, *http.Request) *HTTPError: + return func(c *Context) *HTTPError { return h(c.Response, c.Request) } default: diff --git a/echo_test.go b/echo_test.go index b7a88b58..dfb88b91 100644 --- a/echo_test.go +++ b/echo_test.go @@ -59,15 +59,15 @@ func TestEchoMiddleware(t *testing.T) { b.WriteString("a") }) - // func(*echo.Context) error - e.Use(func(c *Context) error { + // func(*echo.Context) *HTTPError + e.Use(func(c *Context) *HTTPError { b.WriteString("b") return nil }) // func(echo.HandlerFunc) (echo.HandlerFunc, error) e.Use(func(h HandlerFunc) HandlerFunc { - return func(c *Context) error { + return func(c *Context) *HTTPError { b.WriteString("c") return h(c) } @@ -96,8 +96,8 @@ func TestEchoMiddleware(t *testing.T) { b.WriteString("g") }) - // func(http.ResponseWriter, *http.Request) error - e.Use(func(w http.ResponseWriter, r *http.Request) error { + // func(http.ResponseWriter, *http.Request) *HTTPError + e.Use(func(w http.ResponseWriter, r *http.Request) *HTTPError { b.WriteString("h") return nil }) @@ -122,7 +122,7 @@ func TestEchoHandler(t *testing.T) { e := New() // HandlerFunc - e.Get("/1", HandlerFunc(func(c *Context) error { + e.Get("/1", HandlerFunc(func(c *Context) *HTTPError { return c.String(http.StatusOK, "1") })) w := httptest.NewRecorder() @@ -132,8 +132,8 @@ func TestEchoHandler(t *testing.T) { t.Error("body should be 1") } - // func(*echo.Context) error - e.Get("/2", func(c *Context) error { + // func(*echo.Context) *HTTPError + e.Get("/2", func(c *Context) *HTTPError { return c.String(http.StatusOK, "2") }) w = httptest.NewRecorder() @@ -176,8 +176,8 @@ func TestEchoHandler(t *testing.T) { t.Error("body should be 5") } - // func(http.ResponseWriter, *http.Request) error - e.Get("/6", func(w http.ResponseWriter, r *http.Request) error { + // func(http.ResponseWriter, *http.Request) *HTTPError + e.Get("/6", func(w http.ResponseWriter, r *http.Request) *HTTPError { w.Write([]byte("6")) return nil }) diff --git a/examples/crud/server.go b/examples/crud/server.go index 188bec4c..905188e4 100644 --- a/examples/crud/server.go +++ b/examples/crud/server.go @@ -24,34 +24,34 @@ var ( // Handlers //---------- -func createUser(c *echo.Context) error { +func createUser(c *echo.Context) *echo.HTTPError { u := &user{ ID: seq, } - if err := c.Bind(u); err != nil { - return err + if he := c.Bind(u); he != nil { + return he } users[u.ID] = u seq++ return c.JSON(http.StatusCreated, u) } -func getUser(c *echo.Context) error { +func getUser(c *echo.Context) *echo.HTTPError { id, _ := strconv.Atoi(c.Param("id")) return c.JSON(http.StatusOK, users[id]) } -func updateUser(c *echo.Context) error { +func updateUser(c *echo.Context) *echo.HTTPError { u := new(user) - if err := c.Bind(u); err != nil { - return err + if he := c.Bind(u); he != nil { + return he } id, _ := strconv.Atoi(c.Param("id")) users[id].Name = u.Name return c.JSON(http.StatusOK, users[id]) } -func deleteUser(c *echo.Context) error { +func deleteUser(c *echo.Context) *echo.HTTPError { id, _ := strconv.Atoi(c.Param("id")) delete(users, id) return c.NoContent(http.StatusNoContent) diff --git a/examples/hello/server.go b/examples/hello/server.go index 03dc0911..24af7076 100644 --- a/examples/hello/server.go +++ b/examples/hello/server.go @@ -8,8 +8,8 @@ import ( ) // Handler -func hello(c *echo.Context) { - c.String(http.StatusOK, "Hello, World!\n") +func hello(c *echo.Context) *echo.HTTPError { + return c.String(http.StatusOK, "Hello, World!\n") } func main() { diff --git a/examples/web/server.go b/examples/web/server.go index be19dcbd..68cf1037 100644 --- a/examples/web/server.go +++ b/examples/web/server.go @@ -29,15 +29,18 @@ var ( ) // Render HTML -func (t *Template) Render(w io.Writer, name string, data interface{}) error { - return t.templates.ExecuteTemplate(w, name, data) +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 welcome(c *echo.Context) { c.Render(http.StatusOK, "welcome", "Joe") } -func createUser(c *echo.Context) error { +func createUser(c *echo.Context) *echo.HTTPError { u := new(user) if err := c.Bind(u); err != nil { return err @@ -46,11 +49,11 @@ func createUser(c *echo.Context) error { return c.JSON(http.StatusCreated, u) } -func getUsers(c *echo.Context) error { +func getUsers(c *echo.Context) *echo.HTTPError { return c.JSON(http.StatusOK, users) } -func getUser(c *echo.Context) error { +func getUser(c *echo.Context) *echo.HTTPError { return c.JSON(http.StatusOK, users[c.P(0)]) } diff --git a/middleware/logger.go b/middleware/logger.go index 3c5b0c25..04fa673f 100644 --- a/middleware/logger.go +++ b/middleware/logger.go @@ -2,7 +2,6 @@ package middleware import ( "log" - "net/http" "time" "github.com/labstack/echo" @@ -10,10 +9,10 @@ import ( ) func Logger(h echo.HandlerFunc) echo.HandlerFunc { - return func(c *echo.Context) error { + return func(c *echo.Context) *echo.HTTPError { start := time.Now() - if err := h(c); err != nil { - c.Error(http.StatusInternalServerError, err) + if he := h(c); he != nil { + c.Error(he) } end := time.Now() m := c.Request.Method diff --git a/router_test.go b/router_test.go index ffb28521..804b0969 100644 --- a/router_test.go +++ b/router_test.go @@ -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) error { + r.Add(GET, path, func(*Context) *HTTPError { b.WriteString(path) return nil }, nil) @@ -299,7 +299,7 @@ func TestRouterStatic(t *testing.T) { func TestRouterParam(t *testing.T) { r := New().Router - r.Add(GET, "/users/:id", func(c *Context) error { + r.Add(GET, "/users/:id", func(c *Context) *HTTPError { return nil }, nil) h, _ := r.Find(GET, "/users/1", context) @@ -313,7 +313,7 @@ func TestRouterParam(t *testing.T) { func TestRouterTwoParam(t *testing.T) { r := New().Router - r.Add(GET, "/users/:uid/files/:fid", func(*Context) error { + r.Add(GET, "/users/:uid/files/:fid", func(*Context) *HTTPError { return nil }, nil) @@ -336,7 +336,7 @@ func TestRouterTwoParam(t *testing.T) { func TestRouterMatchAny(t *testing.T) { r := New().Router - r.Add(GET, "/users/*", func(*Context) error { + r.Add(GET, "/users/*", func(*Context) *HTTPError { return nil }, nil) @@ -359,7 +359,7 @@ func TestRouterMatchAny(t *testing.T) { func TestRouterMicroParam(t *testing.T) { r := New().Router - r.Add(GET, "/:a/:b/:c", func(c *Context) error { + r.Add(GET, "/:a/:b/:c", func(c *Context) *HTTPError { return nil }, nil) h, _ := r.Find(GET, "/1/2/3", context) @@ -382,11 +382,11 @@ func TestRouterMultiRoute(t *testing.T) { b := new(bytes.Buffer) // Routes - r.Add(GET, "/users", func(*Context) error { + r.Add(GET, "/users", func(*Context) *HTTPError { b.WriteString("/users") return nil }, nil) - r.Add(GET, "/users/:id", func(c *Context) error { + r.Add(GET, "/users/:id", func(c *Context) *HTTPError { return nil }, nil) @@ -421,24 +421,24 @@ func TestRouterConflictingRoute(t *testing.T) { b := new(bytes.Buffer) // Routes - r.Add(GET, "/users", func(*Context) error { + r.Add(GET, "/users", func(*Context) *HTTPError { b.WriteString("/users") return nil }, nil) - r.Add(GET, "/users/new", func(*Context) error { + r.Add(GET, "/users/new", func(*Context) *HTTPError { b.Reset() b.WriteString("/users/new") return nil }, nil) - r.Add(GET, "/users/:id", func(c *Context) error { + r.Add(GET, "/users/:id", func(c *Context) *HTTPError { return nil }, nil) - r.Add(GET, "/users/new/moon", func(*Context) error { + r.Add(GET, "/users/new/moon", func(*Context) *HTTPError { b.Reset() b.WriteString("/users/new/moon") return nil }, nil) - r.Add(GET, "/users/new/:id", func(*Context) error { + r.Add(GET, "/users/new/:id", func(*Context) *HTTPError { return nil }, nil) @@ -532,14 +532,14 @@ func TestRouterParamNames(t *testing.T) { b := new(bytes.Buffer) // Routes - r.Add(GET, "/users", func(*Context) error { + r.Add(GET, "/users", func(*Context) *HTTPError { b.WriteString("/users") return nil }, nil) - r.Add(GET, "/users/:id", func(c *Context) error { + r.Add(GET, "/users/:id", func(c *Context) *HTTPError { return nil }, nil) - r.Add(GET, "/users/:uid/files/:fid", func(c *Context) error { + r.Add(GET, "/users/:uid/files/:fid", func(c *Context) *HTTPError { return nil }, nil) @@ -587,7 +587,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) error { + r.Add(route.method, route.path, func(c *Context) *HTTPError { for i, n := range c.pnames { if n != "" { if ":"+n != c.pvalues[i] { @@ -607,7 +607,7 @@ func TestRouterAPI(t *testing.T) { func TestRouterServeHTTP(t *testing.T) { r := New().Router - r.Add(GET, "/users", func(*Context) error { + r.Add(GET, "/users", func(*Context) *HTTPError { return nil }, nil) @@ -624,31 +624,31 @@ func TestRouterServeHTTP(t *testing.T) { func TestRouterExperiment(t *testing.T) { r := New().Router - r.Add(GET, "/use", func(*Context) error { + r.Add(GET, "/use", func(*Context) *HTTPError { return nil }, nil) - r.Add(GET, "/users/*", func(*Context) error { + r.Add(GET, "/users/*", func(*Context) *HTTPError { return nil }, nil) - r.Add(GET, "/users/", func(*Context) error { + r.Add(GET, "/users/", func(*Context) *HTTPError { return nil }, nil) - r.Add(GET, "/users/new/*", func(*Context) error { + r.Add(GET, "/users/new/*", func(*Context) *HTTPError { return nil }, nil) - r.Add(GET, "/users/new", func(*Context) error { + r.Add(GET, "/users/new", func(*Context) *HTTPError { return nil }, nil) - r.Add(GET, "/users/:uid", func(*Context) error { + r.Add(GET, "/users/:uid", func(*Context) *HTTPError { return nil }, nil) - r.Add(GET, "/users/new/:id", func(*Context) error { + r.Add(GET, "/users/new/:id", func(*Context) *HTTPError { return nil }, nil) - r.Add(GET, "/users/wen", func(*Context) error { + r.Add(GET, "/users/wen", func(*Context) *HTTPError { return nil }, nil) - r.Add(GET, "/users/:uid/files/:fid", func(*Context) error { + r.Add(GET, "/users/:uid/files/:fid", func(*Context) *HTTPError { return nil }, nil) diff --git a/website/docs/guide.md b/website/docs/guide.md index 127dee17..b81035f4 100644 --- a/website/docs/guide.md +++ b/website/docs/guide.md @@ -48,9 +48,7 @@ Default handler sends 404 "Not Found" response. `echo.HTTPErrorHandler(h HTTPErrorHandler)` -Registers a centralized HTTP error handler. - -Default http error handler sends 500 "Internal Server Error" response. +Registers a custom centralized HTTP error handler. ## Routing @@ -70,9 +68,9 @@ 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. +Echo's default handler is `func(*echo.Context) *echo.HTTPError` where `echo.Context` +primarily holds request and response objects. Echo also has a support for other +types of handlers. diff --git a/website/docs/index.md b/website/docs/index.md index b8b050b0..60546d64 100644 --- a/website/docs/index.md +++ b/website/docs/index.md @@ -14,21 +14,21 @@ Echo is a fast HTTP router (zero memory allocation) and micro web framework in G - Extensible middleware/handler, supports: - Middleware - `func(*echo.Context)` - - `func(*echo.Context) error` + - `func(*echo.Context) *echo.HTTPError` - `func(echo.HandlerFunc) echo.HandlerFunc` - `func(http.Handler) http.Handler` - `http.Handler` - `http.HandlerFunc` - `func(http.ResponseWriter, *http.Request)` - - `func(http.ResponseWriter, *http.Request) error` + - `func(http.ResponseWriter, *http.Request) *echo.HTTPError` - Handler - `echo.HandlerFunc` - - `func(*echo.Context) error` + - `func(*echo.Context) *echo.HTTPError` - `func(*echo.Context)` - `http.Handler` - `http.HandlerFunc` - `func(http.ResponseWriter, *http.Request)` - - `func(http.ResponseWriter, *http.Request) error` + - `func(http.ResponseWriter, *http.Request) *echo.HTTPError` - Sub routing with groups. - Handy encoding/decoding functions. - Serve static files, including index. @@ -59,8 +59,8 @@ import ( ) // Handler -func hello(c *echo.Context) { - c.String(http.StatusOK, "Hello, World!\n") +func hello(c *echo.Context) *echo.HTTPError { + return c.String(http.StatusOK, "Hello, World!\n") } func main() { @@ -80,8 +80,8 @@ func main() { `echo.New()` returns a new instance of Echo. -`e.Use(mw.Logger)` adds logging middleware to the chain. It logs every request made to the server, -producing output +`e.Use(mw.Logger)` adds logging middleware to the chain. It logs every request +made to the server, producing output ```sh 2015/04/25 12:15:20 GET / 200 7.544µs