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