mirror of
https://github.com/labstack/echo.git
synced 2024-12-24 20:14:31 +02:00
parent
54d2f72368
commit
f80fff4efb
12
README.md
12
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:
|
- Extensible middleware/handler, supports:
|
||||||
- Middleware
|
- Middleware
|
||||||
- `func(*echo.Context)`
|
- `func(*echo.Context)`
|
||||||
- `func(*echo.Context) error`
|
- `func(*echo.Context) *echo.HTTPError`
|
||||||
- `func(echo.HandlerFunc) echo.HandlerFunc`
|
- `func(echo.HandlerFunc) echo.HandlerFunc`
|
||||||
- `func(http.Handler) http.Handler`
|
- `func(http.Handler) http.Handler`
|
||||||
- `http.Handler`
|
- `http.Handler`
|
||||||
- `http.HandlerFunc`
|
- `http.HandlerFunc`
|
||||||
- `func(http.ResponseWriter, *http.Request)`
|
- `func(http.ResponseWriter, *http.Request)`
|
||||||
- `func(http.ResponseWriter, *http.Request) error`
|
- `func(http.ResponseWriter, *http.Request) *echo.HTTPError`
|
||||||
- Handler
|
- Handler
|
||||||
- `echo.HandlerFunc`
|
- `echo.HandlerFunc`
|
||||||
- `func(*echo.Context) error`
|
- `func(*echo.Context) *echo.HTTPError`
|
||||||
- `func(*echo.Context)`
|
- `func(*echo.Context)`
|
||||||
- `http.Handler`
|
- `http.Handler`
|
||||||
- `http.HandlerFunc`
|
- `http.HandlerFunc`
|
||||||
- `func(http.ResponseWriter, *http.Request)`
|
- `func(http.ResponseWriter, *http.Request)`
|
||||||
- `func(http.ResponseWriter, *http.Request) error`
|
- `func(http.ResponseWriter, *http.Request) *echo.HTTPError`
|
||||||
- Sub routing with groups.
|
- Sub routing with groups.
|
||||||
- Handy encoding/decoding functions.
|
- Handy encoding/decoding functions.
|
||||||
- Serve static files, including index.
|
- Serve static files, including index.
|
||||||
@ -85,8 +85,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Handler
|
// Handler
|
||||||
func hello(c *echo.Context) {
|
func hello(c *echo.Context) *echo.HTTPError {
|
||||||
c.String(http.StatusOK, "Hello, World!\n")
|
return c.String(http.StatusOK, "Hello, World!\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
35
context.go
35
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
|
// Bind binds the request body into specified type v. Default binder does it
|
||||||
// based on Content-Type header.
|
// 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)
|
return c.echo.binder(c.Request, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render invokes the registered HTML template renderer and sends a text/html
|
// Render invokes the registered HTML template renderer and sends a text/html
|
||||||
// response with status code.
|
// 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 {
|
if c.echo.renderer == nil {
|
||||||
return RendererNotRegistered
|
return &HTTPError{Error: RendererNotRegistered}
|
||||||
}
|
}
|
||||||
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)
|
||||||
@ -58,37 +58,44 @@ func (c *Context) Render(code int, name string, data interface{}) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// JSON sends an application/json response with status code.
|
// 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.Header().Set(HeaderContentType, MIMEJSON+"; charset=utf-8")
|
||||||
c.Response.WriteHeader(code)
|
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.
|
// 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.Header().Set(HeaderContentType, MIMEText+"; charset=utf-8")
|
||||||
c.Response.WriteHeader(code)
|
c.Response.WriteHeader(code)
|
||||||
_, err := c.Response.Write([]byte(s))
|
if _, err := c.Response.Write([]byte(s)); err != nil {
|
||||||
return err
|
return &HTTPError{Error: err}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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) error {
|
func (c *Context) HTML(code int, html string) *HTTPError {
|
||||||
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))
|
if _, err := c.Response.Write([]byte(html)); err != nil {
|
||||||
return err
|
return &HTTPError{Error: err}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NoContent sends a response with no body and a status code.
|
// 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)
|
c.Response.WriteHeader(code)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error invokes the registered HTTP error handler.
|
// Error invokes the registered HTTP error handler.
|
||||||
func (c *Context) Error(code int, err error) {
|
func (c *Context) Error(he *HTTPError) {
|
||||||
c.echo.httpErrorHandler(code, err, c)
|
c.echo.httpErrorHandler(he, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get retrieves data from the context.
|
// Get retrieves data from the context.
|
||||||
|
@ -16,8 +16,11 @@ type (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func (t *Template) Render(w io.Writer, name string, data interface{}) error {
|
func (t *Template) Render(w io.Writer, name string, data interface{}) *HTTPError {
|
||||||
return t.templates.ExecuteTemplate(w, name, data)
|
if err := t.templates.ExecuteTemplate(w, name, data); err != nil {
|
||||||
|
return &HTTPError{Error: err}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestContext(t *testing.T) {
|
func TestContext(t *testing.T) {
|
||||||
@ -38,24 +41,24 @@ func TestContext(t *testing.T) {
|
|||||||
// JSON
|
// JSON
|
||||||
r.Header.Set(HeaderContentType, MIMEJSON)
|
r.Header.Set(HeaderContentType, MIMEJSON)
|
||||||
u2 := new(user)
|
u2 := new(user)
|
||||||
if err := c.Bind(u2); err != nil {
|
if he := c.Bind(u2); he != nil {
|
||||||
t.Error(err)
|
t.Errorf("bind %#v", he)
|
||||||
}
|
}
|
||||||
verifyUser(u2, t)
|
verifyUser(u2, t)
|
||||||
|
|
||||||
// FORM
|
// FORM
|
||||||
r.Header.Set(HeaderContentType, MIMEForm)
|
r.Header.Set(HeaderContentType, MIMEForm)
|
||||||
u2 = new(user)
|
u2 = new(user)
|
||||||
if err := c.Bind(u2); err != nil {
|
if he := c.Bind(u2); he != nil {
|
||||||
t.Error(err)
|
t.Errorf("bind %#v", he)
|
||||||
}
|
}
|
||||||
// TODO: add verification
|
// TODO: add verification
|
||||||
|
|
||||||
// Unsupported
|
// Unsupported
|
||||||
r.Header.Set(HeaderContentType, "")
|
r.Header.Set(HeaderContentType, "")
|
||||||
u2 = new(user)
|
u2 = new(user)
|
||||||
if err := c.Bind(u2); err == nil {
|
if he := c.Bind(u2); he == nil {
|
||||||
t.Error(err)
|
t.Errorf("bind %#v", he)
|
||||||
}
|
}
|
||||||
// TODO: add verification
|
// TODO: add verification
|
||||||
|
|
||||||
@ -87,33 +90,33 @@ func TestContext(t *testing.T) {
|
|||||||
templates: template.Must(template.New("hello").Parse("{{.}}")),
|
templates: template.Must(template.New("hello").Parse("{{.}}")),
|
||||||
}
|
}
|
||||||
c.echo.renderer = tpl
|
c.echo.renderer = tpl
|
||||||
if err := c.Render(http.StatusOK, "hello", "Joe"); err != nil {
|
if he := c.Render(http.StatusOK, "hello", "Joe"); he != nil {
|
||||||
t.Errorf("render %v", err)
|
t.Errorf("render %#v", he.Error)
|
||||||
}
|
}
|
||||||
c.echo.renderer = nil
|
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")
|
t.Error("render should error out")
|
||||||
}
|
}
|
||||||
|
|
||||||
// JSON
|
// JSON
|
||||||
r.Header.Set(HeaderAccept, MIMEJSON)
|
r.Header.Set(HeaderAccept, MIMEJSON)
|
||||||
c.Response.committed = false
|
c.Response.committed = false
|
||||||
if err := c.JSON(http.StatusOK, u1); err != nil {
|
if he := c.JSON(http.StatusOK, u1); he != nil {
|
||||||
t.Errorf("json %v", err)
|
t.Errorf("json %#v", he)
|
||||||
}
|
}
|
||||||
|
|
||||||
// String
|
// String
|
||||||
r.Header.Set(HeaderAccept, MIMEText)
|
r.Header.Set(HeaderAccept, MIMEText)
|
||||||
c.Response.committed = false
|
c.Response.committed = false
|
||||||
if err := c.String(http.StatusOK, "Hello, World!"); err != nil {
|
if he := c.String(http.StatusOK, "Hello, World!"); he != nil {
|
||||||
t.Errorf("string %v", err)
|
t.Errorf("string %#v", he.Error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTML
|
// HTML
|
||||||
r.Header.Set(HeaderAccept, MIMEHTML)
|
r.Header.Set(HeaderAccept, MIMEHTML)
|
||||||
c.Response.committed = false
|
c.Response.committed = false
|
||||||
if err := c.HTML(http.StatusOK, "Hello, <strong>World!</strong>"); err != nil {
|
if he := c.HTML(http.StatusOK, "Hello, <strong>World!</strong>"); he != nil {
|
||||||
t.Errorf("html %v", err)
|
t.Errorf("html %v", he.Error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Redirect
|
// Redirect
|
||||||
|
101
echo.go
101
echo.go
@ -13,7 +13,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/labstack/gommon/color"
|
|
||||||
"github.com/mattn/go-colorable"
|
"github.com/mattn/go-colorable"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -30,22 +29,27 @@ type (
|
|||||||
uris map[Handler]string
|
uris map[Handler]string
|
||||||
pool sync.Pool
|
pool sync.Pool
|
||||||
}
|
}
|
||||||
|
HTTPError struct {
|
||||||
|
Code int
|
||||||
|
Message string
|
||||||
|
Error error
|
||||||
|
}
|
||||||
Middleware interface{}
|
Middleware interface{}
|
||||||
MiddlewareFunc func(HandlerFunc) HandlerFunc
|
MiddlewareFunc func(HandlerFunc) HandlerFunc
|
||||||
Handler interface{}
|
Handler interface{}
|
||||||
HandlerFunc func(*Context) error
|
HandlerFunc func(*Context) *HTTPError
|
||||||
|
|
||||||
// HTTPErrorHandler is a centralized HTTP error handler.
|
// 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.
|
// Renderer is the interface that wraps the Render method.
|
||||||
//
|
//
|
||||||
// Render renders the HTML template with given name and specified data.
|
// Render renders the HTML template with given name and specified data.
|
||||||
// It writes the output to w.
|
// It writes the output to w.
|
||||||
Renderer interface {
|
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) {
|
e.NotFoundHandler(func(c *Context) {
|
||||||
http.Error(c.Response, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
http.Error(c.Response, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
||||||
})
|
})
|
||||||
e.HTTPErrorHandler(func(code int, err error, c *Context) {
|
e.HTTPErrorHandler(func(he *HTTPError, c *Context) {
|
||||||
if err != nil {
|
if he.Code == 0 {
|
||||||
// TODO: Warning
|
he.Code = http.StatusInternalServerError
|
||||||
log.Printf("echo: %s", color.Yellow("http error handler not registered"))
|
|
||||||
http.Error(c.Response, err.Error(), code)
|
|
||||||
}
|
}
|
||||||
|
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)
|
ct := r.Header.Get(HeaderContentType)
|
||||||
|
err := UnsupportedMediaType
|
||||||
if strings.HasPrefix(ct, MIMEJSON) {
|
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) {
|
} else if strings.HasPrefix(ct, MIMEForm) {
|
||||||
return nil
|
err = nil
|
||||||
}
|
}
|
||||||
return UnsupportedMediaType
|
if err != nil {
|
||||||
|
return &HTTPError{Error: err}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -272,7 +282,7 @@ func (e *Echo) add(method, path string, h Handler) {
|
|||||||
// Static serves static files.
|
// Static serves static files.
|
||||||
func (e *Echo) Static(path, root string) {
|
func (e *Echo) Static(path, root string) {
|
||||||
fs := http.StripPrefix(path, http.FileServer(http.Dir(root)))
|
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)
|
fs.ServeHTTP(c.Response, c.Request)
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
@ -280,7 +290,7 @@ func (e *Echo) Static(path, root string) {
|
|||||||
|
|
||||||
// ServeFile serves a file.
|
// ServeFile serves a file.
|
||||||
func (e *Echo) ServeFile(path, file string) {
|
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)
|
http.ServeFile(c.Response, c.Request, file)
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
@ -308,8 +318,8 @@ func (e *Echo) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Execute chain
|
// Execute chain
|
||||||
if err := h(c); err != nil {
|
if he := h(c); he != nil {
|
||||||
e.httpErrorHandler(http.StatusInternalServerError, err, c)
|
e.httpErrorHandler(he, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
e.pool.Put(c)
|
e.pool.Put(c)
|
||||||
@ -342,16 +352,19 @@ func wrapM(m Middleware) MiddlewareFunc {
|
|||||||
switch m := m.(type) {
|
switch m := m.(type) {
|
||||||
case func(*Context):
|
case func(*Context):
|
||||||
return func(h HandlerFunc) HandlerFunc {
|
return func(h HandlerFunc) HandlerFunc {
|
||||||
return func(c *Context) error {
|
return func(c *Context) *HTTPError {
|
||||||
m(c)
|
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(h HandlerFunc) HandlerFunc {
|
||||||
return func(c *Context) error {
|
return func(c *Context) *HTTPError {
|
||||||
if err := m(c); err != nil {
|
if he := m(c); he != nil {
|
||||||
return err
|
return he
|
||||||
}
|
}
|
||||||
return h(c)
|
return h(c)
|
||||||
}
|
}
|
||||||
@ -360,36 +373,42 @@ func wrapM(m Middleware) MiddlewareFunc {
|
|||||||
return m
|
return m
|
||||||
case func(http.Handler) http.Handler:
|
case func(http.Handler) http.Handler:
|
||||||
return func(h HandlerFunc) HandlerFunc {
|
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) {
|
m(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
c.Response.Writer = w
|
c.Response.Writer = w
|
||||||
c.Request = r
|
c.Request = r
|
||||||
err = h(c)
|
he = h(c)
|
||||||
})).ServeHTTP(c.Response.Writer, c.Request)
|
})).ServeHTTP(c.Response.Writer, c.Request)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case http.Handler, http.HandlerFunc:
|
case http.Handler, http.HandlerFunc:
|
||||||
return func(h HandlerFunc) 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)
|
m.(http.Handler).ServeHTTP(c.Response.Writer, c.Request)
|
||||||
return h(c)
|
return h(c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case func(http.ResponseWriter, *http.Request):
|
case func(http.ResponseWriter, *http.Request):
|
||||||
return func(h HandlerFunc) HandlerFunc {
|
return func(h HandlerFunc) HandlerFunc {
|
||||||
return func(c *Context) error {
|
return func(c *Context) *HTTPError {
|
||||||
m(c.Response.Writer, c.Request)
|
m(c.Response, c.Request)
|
||||||
return h(c)
|
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(h HandlerFunc) HandlerFunc {
|
||||||
return func(c *Context) error {
|
return func(c *Context) *HTTPError {
|
||||||
if err := m(c.Response.Writer, c.Request); err != nil {
|
if he := m(c.Response, c.Request); he != nil {
|
||||||
return err
|
return he
|
||||||
}
|
}
|
||||||
return h(c)
|
if !c.Response.committed {
|
||||||
|
h(c)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -402,25 +421,25 @@ func wrapH(h Handler) HandlerFunc {
|
|||||||
switch h := h.(type) {
|
switch h := h.(type) {
|
||||||
case HandlerFunc:
|
case HandlerFunc:
|
||||||
return h
|
return h
|
||||||
case func(*Context) error:
|
case func(*Context) *HTTPError:
|
||||||
return h
|
return h
|
||||||
case func(*Context):
|
case func(*Context):
|
||||||
return func(c *Context) error {
|
return func(c *Context) *HTTPError {
|
||||||
h(c)
|
h(c)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
case http.Handler, http.HandlerFunc:
|
case http.Handler, http.HandlerFunc:
|
||||||
return func(c *Context) error {
|
return func(c *Context) *HTTPError {
|
||||||
h.(http.Handler).ServeHTTP(c.Response, c.Request)
|
h.(http.Handler).ServeHTTP(c.Response, c.Request)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
case func(http.ResponseWriter, *http.Request):
|
case func(http.ResponseWriter, *http.Request):
|
||||||
return func(c *Context) error {
|
return func(c *Context) *HTTPError {
|
||||||
h(c.Response, c.Request)
|
h(c.Response, c.Request)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
case func(http.ResponseWriter, *http.Request) error:
|
case func(http.ResponseWriter, *http.Request) *HTTPError:
|
||||||
return func(c *Context) error {
|
return func(c *Context) *HTTPError {
|
||||||
return h(c.Response, c.Request)
|
return h(c.Response, c.Request)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
20
echo_test.go
20
echo_test.go
@ -59,15 +59,15 @@ func TestEchoMiddleware(t *testing.T) {
|
|||||||
b.WriteString("a")
|
b.WriteString("a")
|
||||||
})
|
})
|
||||||
|
|
||||||
// func(*echo.Context) error
|
// func(*echo.Context) *HTTPError
|
||||||
e.Use(func(c *Context) error {
|
e.Use(func(c *Context) *HTTPError {
|
||||||
b.WriteString("b")
|
b.WriteString("b")
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
// func(echo.HandlerFunc) (echo.HandlerFunc, error)
|
// func(echo.HandlerFunc) (echo.HandlerFunc, error)
|
||||||
e.Use(func(h HandlerFunc) HandlerFunc {
|
e.Use(func(h HandlerFunc) HandlerFunc {
|
||||||
return func(c *Context) error {
|
return func(c *Context) *HTTPError {
|
||||||
b.WriteString("c")
|
b.WriteString("c")
|
||||||
return h(c)
|
return h(c)
|
||||||
}
|
}
|
||||||
@ -96,8 +96,8 @@ func TestEchoMiddleware(t *testing.T) {
|
|||||||
b.WriteString("g")
|
b.WriteString("g")
|
||||||
})
|
})
|
||||||
|
|
||||||
// func(http.ResponseWriter, *http.Request) error
|
// func(http.ResponseWriter, *http.Request) *HTTPError
|
||||||
e.Use(func(w http.ResponseWriter, r *http.Request) error {
|
e.Use(func(w http.ResponseWriter, r *http.Request) *HTTPError {
|
||||||
b.WriteString("h")
|
b.WriteString("h")
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
@ -122,7 +122,7 @@ func TestEchoHandler(t *testing.T) {
|
|||||||
e := New()
|
e := New()
|
||||||
|
|
||||||
// HandlerFunc
|
// HandlerFunc
|
||||||
e.Get("/1", HandlerFunc(func(c *Context) error {
|
e.Get("/1", HandlerFunc(func(c *Context) *HTTPError {
|
||||||
return c.String(http.StatusOK, "1")
|
return c.String(http.StatusOK, "1")
|
||||||
}))
|
}))
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
@ -132,8 +132,8 @@ func TestEchoHandler(t *testing.T) {
|
|||||||
t.Error("body should be 1")
|
t.Error("body should be 1")
|
||||||
}
|
}
|
||||||
|
|
||||||
// func(*echo.Context) error
|
// func(*echo.Context) *HTTPError
|
||||||
e.Get("/2", func(c *Context) error {
|
e.Get("/2", func(c *Context) *HTTPError {
|
||||||
return c.String(http.StatusOK, "2")
|
return c.String(http.StatusOK, "2")
|
||||||
})
|
})
|
||||||
w = httptest.NewRecorder()
|
w = httptest.NewRecorder()
|
||||||
@ -176,8 +176,8 @@ func TestEchoHandler(t *testing.T) {
|
|||||||
t.Error("body should be 5")
|
t.Error("body should be 5")
|
||||||
}
|
}
|
||||||
|
|
||||||
// func(http.ResponseWriter, *http.Request) error
|
// func(http.ResponseWriter, *http.Request) *HTTPError
|
||||||
e.Get("/6", func(w http.ResponseWriter, r *http.Request) error {
|
e.Get("/6", func(w http.ResponseWriter, r *http.Request) *HTTPError {
|
||||||
w.Write([]byte("6"))
|
w.Write([]byte("6"))
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
@ -24,34 +24,34 @@ var (
|
|||||||
// Handlers
|
// Handlers
|
||||||
//----------
|
//----------
|
||||||
|
|
||||||
func createUser(c *echo.Context) error {
|
func createUser(c *echo.Context) *echo.HTTPError {
|
||||||
u := &user{
|
u := &user{
|
||||||
ID: seq,
|
ID: seq,
|
||||||
}
|
}
|
||||||
if err := c.Bind(u); err != nil {
|
if he := c.Bind(u); he != nil {
|
||||||
return err
|
return he
|
||||||
}
|
}
|
||||||
users[u.ID] = u
|
users[u.ID] = u
|
||||||
seq++
|
seq++
|
||||||
return c.JSON(http.StatusCreated, u)
|
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"))
|
id, _ := strconv.Atoi(c.Param("id"))
|
||||||
return c.JSON(http.StatusOK, users[id])
|
return c.JSON(http.StatusOK, users[id])
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateUser(c *echo.Context) error {
|
func updateUser(c *echo.Context) *echo.HTTPError {
|
||||||
u := new(user)
|
u := new(user)
|
||||||
if err := c.Bind(u); err != nil {
|
if he := c.Bind(u); he != nil {
|
||||||
return err
|
return he
|
||||||
}
|
}
|
||||||
id, _ := strconv.Atoi(c.Param("id"))
|
id, _ := strconv.Atoi(c.Param("id"))
|
||||||
users[id].Name = u.Name
|
users[id].Name = u.Name
|
||||||
return c.JSON(http.StatusOK, users[id])
|
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"))
|
id, _ := strconv.Atoi(c.Param("id"))
|
||||||
delete(users, id)
|
delete(users, id)
|
||||||
return c.NoContent(http.StatusNoContent)
|
return c.NoContent(http.StatusNoContent)
|
||||||
|
@ -8,8 +8,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Handler
|
// Handler
|
||||||
func hello(c *echo.Context) {
|
func hello(c *echo.Context) *echo.HTTPError {
|
||||||
c.String(http.StatusOK, "Hello, World!\n")
|
return c.String(http.StatusOK, "Hello, World!\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
@ -29,15 +29,18 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Render HTML
|
// Render HTML
|
||||||
func (t *Template) Render(w io.Writer, name string, data interface{}) error {
|
func (t *Template) Render(w io.Writer, name string, data interface{}) *echo.HTTPError {
|
||||||
return t.templates.ExecuteTemplate(w, name, data)
|
if err := t.templates.ExecuteTemplate(w, name, data); err != nil {
|
||||||
|
return &echo.HTTPError{Error: err}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func welcome(c *echo.Context) {
|
func welcome(c *echo.Context) {
|
||||||
c.Render(http.StatusOK, "welcome", "Joe")
|
c.Render(http.StatusOK, "welcome", "Joe")
|
||||||
}
|
}
|
||||||
|
|
||||||
func createUser(c *echo.Context) error {
|
func createUser(c *echo.Context) *echo.HTTPError {
|
||||||
u := new(user)
|
u := new(user)
|
||||||
if err := c.Bind(u); err != nil {
|
if err := c.Bind(u); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -46,11 +49,11 @@ func createUser(c *echo.Context) error {
|
|||||||
return c.JSON(http.StatusCreated, u)
|
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)
|
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)])
|
return c.JSON(http.StatusOK, users[c.P(0)])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,6 @@ package middleware
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/labstack/echo"
|
"github.com/labstack/echo"
|
||||||
@ -10,10 +9,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func Logger(h echo.HandlerFunc) echo.HandlerFunc {
|
func Logger(h echo.HandlerFunc) echo.HandlerFunc {
|
||||||
return func(c *echo.Context) error {
|
return func(c *echo.Context) *echo.HTTPError {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
if err := h(c); err != nil {
|
if he := h(c); he != nil {
|
||||||
c.Error(http.StatusInternalServerError, err)
|
c.Error(he)
|
||||||
}
|
}
|
||||||
end := time.Now()
|
end := time.Now()
|
||||||
m := c.Request.Method
|
m := c.Request.Method
|
||||||
|
@ -283,7 +283,7 @@ func TestRouterStatic(t *testing.T) {
|
|||||||
r := New().Router
|
r := New().Router
|
||||||
b := new(bytes.Buffer)
|
b := new(bytes.Buffer)
|
||||||
path := "/folders/a/files/echo.gif"
|
path := "/folders/a/files/echo.gif"
|
||||||
r.Add(GET, path, func(*Context) error {
|
r.Add(GET, path, func(*Context) *HTTPError {
|
||||||
b.WriteString(path)
|
b.WriteString(path)
|
||||||
return nil
|
return nil
|
||||||
}, nil)
|
}, nil)
|
||||||
@ -299,7 +299,7 @@ func TestRouterStatic(t *testing.T) {
|
|||||||
|
|
||||||
func TestRouterParam(t *testing.T) {
|
func TestRouterParam(t *testing.T) {
|
||||||
r := New().Router
|
r := New().Router
|
||||||
r.Add(GET, "/users/:id", func(c *Context) error {
|
r.Add(GET, "/users/:id", func(c *Context) *HTTPError {
|
||||||
return nil
|
return nil
|
||||||
}, nil)
|
}, nil)
|
||||||
h, _ := r.Find(GET, "/users/1", context)
|
h, _ := r.Find(GET, "/users/1", context)
|
||||||
@ -313,7 +313,7 @@ func TestRouterParam(t *testing.T) {
|
|||||||
|
|
||||||
func TestRouterTwoParam(t *testing.T) {
|
func TestRouterTwoParam(t *testing.T) {
|
||||||
r := New().Router
|
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
|
return nil
|
||||||
}, nil)
|
}, nil)
|
||||||
|
|
||||||
@ -336,7 +336,7 @@ func TestRouterTwoParam(t *testing.T) {
|
|||||||
|
|
||||||
func TestRouterMatchAny(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) *HTTPError {
|
||||||
return nil
|
return nil
|
||||||
}, nil)
|
}, nil)
|
||||||
|
|
||||||
@ -359,7 +359,7 @@ func TestRouterMatchAny(t *testing.T) {
|
|||||||
|
|
||||||
func TestRouterMicroParam(t *testing.T) {
|
func TestRouterMicroParam(t *testing.T) {
|
||||||
r := New().Router
|
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
|
return nil
|
||||||
}, nil)
|
}, nil)
|
||||||
h, _ := r.Find(GET, "/1/2/3", context)
|
h, _ := r.Find(GET, "/1/2/3", context)
|
||||||
@ -382,11 +382,11 @@ func TestRouterMultiRoute(t *testing.T) {
|
|||||||
b := new(bytes.Buffer)
|
b := new(bytes.Buffer)
|
||||||
|
|
||||||
// Routes
|
// Routes
|
||||||
r.Add(GET, "/users", func(*Context) error {
|
r.Add(GET, "/users", func(*Context) *HTTPError {
|
||||||
b.WriteString("/users")
|
b.WriteString("/users")
|
||||||
return nil
|
return nil
|
||||||
}, nil)
|
}, nil)
|
||||||
r.Add(GET, "/users/:id", func(c *Context) error {
|
r.Add(GET, "/users/:id", func(c *Context) *HTTPError {
|
||||||
return nil
|
return nil
|
||||||
}, nil)
|
}, nil)
|
||||||
|
|
||||||
@ -421,24 +421,24 @@ func TestRouterConflictingRoute(t *testing.T) {
|
|||||||
b := new(bytes.Buffer)
|
b := new(bytes.Buffer)
|
||||||
|
|
||||||
// Routes
|
// Routes
|
||||||
r.Add(GET, "/users", func(*Context) error {
|
r.Add(GET, "/users", func(*Context) *HTTPError {
|
||||||
b.WriteString("/users")
|
b.WriteString("/users")
|
||||||
return nil
|
return nil
|
||||||
}, nil)
|
}, nil)
|
||||||
r.Add(GET, "/users/new", func(*Context) error {
|
r.Add(GET, "/users/new", func(*Context) *HTTPError {
|
||||||
b.Reset()
|
b.Reset()
|
||||||
b.WriteString("/users/new")
|
b.WriteString("/users/new")
|
||||||
return nil
|
return nil
|
||||||
}, nil)
|
}, nil)
|
||||||
r.Add(GET, "/users/:id", func(c *Context) error {
|
r.Add(GET, "/users/:id", func(c *Context) *HTTPError {
|
||||||
return nil
|
return nil
|
||||||
}, nil)
|
}, nil)
|
||||||
r.Add(GET, "/users/new/moon", func(*Context) error {
|
r.Add(GET, "/users/new/moon", func(*Context) *HTTPError {
|
||||||
b.Reset()
|
b.Reset()
|
||||||
b.WriteString("/users/new/moon")
|
b.WriteString("/users/new/moon")
|
||||||
return nil
|
return nil
|
||||||
}, nil)
|
}, nil)
|
||||||
r.Add(GET, "/users/new/:id", func(*Context) error {
|
r.Add(GET, "/users/new/:id", func(*Context) *HTTPError {
|
||||||
return nil
|
return nil
|
||||||
}, nil)
|
}, nil)
|
||||||
|
|
||||||
@ -532,14 +532,14 @@ func TestRouterParamNames(t *testing.T) {
|
|||||||
b := new(bytes.Buffer)
|
b := new(bytes.Buffer)
|
||||||
|
|
||||||
// Routes
|
// Routes
|
||||||
r.Add(GET, "/users", func(*Context) error {
|
r.Add(GET, "/users", func(*Context) *HTTPError {
|
||||||
b.WriteString("/users")
|
b.WriteString("/users")
|
||||||
return nil
|
return nil
|
||||||
}, nil)
|
}, nil)
|
||||||
r.Add(GET, "/users/:id", func(c *Context) error {
|
r.Add(GET, "/users/:id", func(c *Context) *HTTPError {
|
||||||
return nil
|
return nil
|
||||||
}, 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
|
return nil
|
||||||
}, nil)
|
}, nil)
|
||||||
|
|
||||||
@ -587,7 +587,7 @@ func TestRouterParamNames(t *testing.T) {
|
|||||||
func TestRouterAPI(t *testing.T) {
|
func TestRouterAPI(t *testing.T) {
|
||||||
r := New().Router
|
r := New().Router
|
||||||
for _, route := range api {
|
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 {
|
for i, n := range c.pnames {
|
||||||
if n != "" {
|
if n != "" {
|
||||||
if ":"+n != c.pvalues[i] {
|
if ":"+n != c.pvalues[i] {
|
||||||
@ -607,7 +607,7 @@ func TestRouterAPI(t *testing.T) {
|
|||||||
|
|
||||||
func TestRouterServeHTTP(t *testing.T) {
|
func TestRouterServeHTTP(t *testing.T) {
|
||||||
r := New().Router
|
r := New().Router
|
||||||
r.Add(GET, "/users", func(*Context) error {
|
r.Add(GET, "/users", func(*Context) *HTTPError {
|
||||||
return nil
|
return nil
|
||||||
}, nil)
|
}, nil)
|
||||||
|
|
||||||
@ -624,31 +624,31 @@ func TestRouterServeHTTP(t *testing.T) {
|
|||||||
|
|
||||||
func TestRouterExperiment(t *testing.T) {
|
func TestRouterExperiment(t *testing.T) {
|
||||||
r := New().Router
|
r := New().Router
|
||||||
r.Add(GET, "/use", func(*Context) error {
|
r.Add(GET, "/use", func(*Context) *HTTPError {
|
||||||
return nil
|
return nil
|
||||||
}, nil)
|
}, nil)
|
||||||
r.Add(GET, "/users/*", func(*Context) error {
|
r.Add(GET, "/users/*", func(*Context) *HTTPError {
|
||||||
return nil
|
return nil
|
||||||
}, nil)
|
}, nil)
|
||||||
r.Add(GET, "/users/", func(*Context) error {
|
r.Add(GET, "/users/", func(*Context) *HTTPError {
|
||||||
return nil
|
return nil
|
||||||
}, nil)
|
}, nil)
|
||||||
r.Add(GET, "/users/new/*", func(*Context) error {
|
r.Add(GET, "/users/new/*", func(*Context) *HTTPError {
|
||||||
return nil
|
return nil
|
||||||
}, nil)
|
}, nil)
|
||||||
r.Add(GET, "/users/new", func(*Context) error {
|
r.Add(GET, "/users/new", func(*Context) *HTTPError {
|
||||||
return nil
|
return nil
|
||||||
}, nil)
|
}, nil)
|
||||||
r.Add(GET, "/users/:uid", func(*Context) error {
|
r.Add(GET, "/users/:uid", func(*Context) *HTTPError {
|
||||||
return nil
|
return nil
|
||||||
}, nil)
|
}, nil)
|
||||||
r.Add(GET, "/users/new/:id", func(*Context) error {
|
r.Add(GET, "/users/new/:id", func(*Context) *HTTPError {
|
||||||
return nil
|
return nil
|
||||||
}, nil)
|
}, nil)
|
||||||
r.Add(GET, "/users/wen", func(*Context) error {
|
r.Add(GET, "/users/wen", func(*Context) *HTTPError {
|
||||||
return nil
|
return nil
|
||||||
}, nil)
|
}, nil)
|
||||||
r.Add(GET, "/users/:uid/files/:fid", func(*Context) error {
|
r.Add(GET, "/users/:uid/files/:fid", func(*Context) *HTTPError {
|
||||||
return nil
|
return nil
|
||||||
}, nil)
|
}, nil)
|
||||||
|
|
||||||
|
@ -48,9 +48,7 @@ Default handler sends 404 "Not Found" response.
|
|||||||
|
|
||||||
`echo.HTTPErrorHandler(h HTTPErrorHandler)`
|
`echo.HTTPErrorHandler(h HTTPErrorHandler)`
|
||||||
|
|
||||||
Registers a centralized HTTP error handler.
|
Registers a custom centralized HTTP error handler.
|
||||||
|
|
||||||
Default http error handler sends 500 "Internal Server Error" response.
|
|
||||||
|
|
||||||
## Routing
|
## Routing
|
||||||
|
|
||||||
@ -70,9 +68,9 @@ echo.Get("/hello", func(*echo.Context) {
|
|||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
Echo's default handler is `func(*echo.Context) error` where `echo.Context` primarily
|
Echo's default handler is `func(*echo.Context) *echo.HTTPError` where `echo.Context`
|
||||||
holds request and response objects. Echo also has a support for other types of
|
primarily holds request and response objects. Echo also has a support for other
|
||||||
handlers.
|
types of handlers.
|
||||||
|
|
||||||
<!-- TODO mention about not able to take advantage -->
|
<!-- TODO mention about not able to take advantage -->
|
||||||
|
|
||||||
|
@ -14,21 +14,21 @@ Echo is a fast HTTP router (zero memory allocation) and micro web framework in G
|
|||||||
- Extensible middleware/handler, supports:
|
- Extensible middleware/handler, supports:
|
||||||
- Middleware
|
- Middleware
|
||||||
- `func(*echo.Context)`
|
- `func(*echo.Context)`
|
||||||
- `func(*echo.Context) error`
|
- `func(*echo.Context) *echo.HTTPError`
|
||||||
- `func(echo.HandlerFunc) echo.HandlerFunc`
|
- `func(echo.HandlerFunc) echo.HandlerFunc`
|
||||||
- `func(http.Handler) http.Handler`
|
- `func(http.Handler) http.Handler`
|
||||||
- `http.Handler`
|
- `http.Handler`
|
||||||
- `http.HandlerFunc`
|
- `http.HandlerFunc`
|
||||||
- `func(http.ResponseWriter, *http.Request)`
|
- `func(http.ResponseWriter, *http.Request)`
|
||||||
- `func(http.ResponseWriter, *http.Request) error`
|
- `func(http.ResponseWriter, *http.Request) *echo.HTTPError`
|
||||||
- Handler
|
- Handler
|
||||||
- `echo.HandlerFunc`
|
- `echo.HandlerFunc`
|
||||||
- `func(*echo.Context) error`
|
- `func(*echo.Context) *echo.HTTPError`
|
||||||
- `func(*echo.Context)`
|
- `func(*echo.Context)`
|
||||||
- `http.Handler`
|
- `http.Handler`
|
||||||
- `http.HandlerFunc`
|
- `http.HandlerFunc`
|
||||||
- `func(http.ResponseWriter, *http.Request)`
|
- `func(http.ResponseWriter, *http.Request)`
|
||||||
- `func(http.ResponseWriter, *http.Request) error`
|
- `func(http.ResponseWriter, *http.Request) *echo.HTTPError`
|
||||||
- Sub routing with groups.
|
- Sub routing with groups.
|
||||||
- Handy encoding/decoding functions.
|
- Handy encoding/decoding functions.
|
||||||
- Serve static files, including index.
|
- Serve static files, including index.
|
||||||
@ -59,8 +59,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Handler
|
// Handler
|
||||||
func hello(c *echo.Context) {
|
func hello(c *echo.Context) *echo.HTTPError {
|
||||||
c.String(http.StatusOK, "Hello, World!\n")
|
return c.String(http.StatusOK, "Hello, World!\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@ -80,8 +80,8 @@ func main() {
|
|||||||
|
|
||||||
`echo.New()` returns a new instance of Echo.
|
`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,
|
`e.Use(mw.Logger)` adds logging middleware to the chain. It logs every request
|
||||||
producing output
|
made to the server, producing output
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
2015/04/25 12:15:20 GET / 200 7.544µs
|
2015/04/25 12:15:20 GET / 200 7.544µs
|
||||||
|
Loading…
Reference in New Issue
Block a user