Skip to content

Commit 13ac746

Browse files
committed
Refactored Echo.HandlerFunc, added WebSocket support.
Signed-off-by: Vishal Rana <[email protected]>
1 parent 60a377a commit 13ac746

16 files changed

+186
-136
lines changed

context.go

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package echo
33
import (
44
"encoding/json"
55
"net/http"
6+
7+
"golang.org/x/net/websocket"
68
)
79

810
type (
@@ -11,6 +13,7 @@ type (
1113
Context struct {
1214
Request *http.Request
1315
Response *Response
16+
Socket *websocket.Conn
1417
pnames []string
1518
pvalues []string
1619
store store
@@ -53,60 +56,53 @@ func (c *Context) Param(name string) (value string) {
5356

5457
// Bind binds the request body into specified type v. Default binder does it
5558
// based on Content-Type header.
56-
func (c *Context) Bind(i interface{}) *HTTPError {
59+
func (c *Context) Bind(i interface{}) error {
5760
return c.echo.binder(c.Request, i)
5861
}
5962

6063
// Render invokes the registered HTML template renderer and sends a text/html
6164
// response with status code.
62-
func (c *Context) Render(code int, name string, data interface{}) *HTTPError {
65+
func (c *Context) Render(code int, name string, data interface{}) error {
6366
if c.echo.renderer == nil {
64-
return &HTTPError{Error: RendererNotRegistered}
67+
return RendererNotRegistered
6568
}
6669
c.Response.Header().Set(ContentType, TextHTML+"; charset=utf-8")
6770
c.Response.WriteHeader(code)
6871
return c.echo.renderer.Render(c.Response, name, data)
6972
}
7073

7174
// JSON sends an application/json response with status code.
72-
func (c *Context) JSON(code int, i interface{}) *HTTPError {
75+
func (c *Context) JSON(code int, i interface{}) error {
7376
c.Response.Header().Set(ContentType, ApplicationJSON+"; charset=utf-8")
7477
c.Response.WriteHeader(code)
75-
if err := json.NewEncoder(c.Response).Encode(i); err != nil {
76-
return &HTTPError{Error: err}
77-
}
78-
return nil
78+
return json.NewEncoder(c.Response).Encode(i)
7979
}
8080

8181
// String sends a text/plain response with status code.
82-
func (c *Context) String(code int, s string) *HTTPError {
82+
func (c *Context) String(code int, s string) error {
8383
c.Response.Header().Set(ContentType, TextPlain+"; charset=utf-8")
8484
c.Response.WriteHeader(code)
85-
if _, err := c.Response.Write([]byte(s)); err != nil {
86-
return &HTTPError{Error: err}
87-
}
88-
return nil
85+
_, err := c.Response.Write([]byte(s))
86+
return err
8987
}
9088

9189
// HTML sends a text/html response with status code.
92-
func (c *Context) HTML(code int, html string) *HTTPError {
90+
func (c *Context) HTML(code int, html string) error {
9391
c.Response.Header().Set(ContentType, TextHTML+"; charset=utf-8")
9492
c.Response.WriteHeader(code)
95-
if _, err := c.Response.Write([]byte(html)); err != nil {
96-
return &HTTPError{Error: err}
97-
}
98-
return nil
93+
_, err := c.Response.Write([]byte(html))
94+
return err
9995
}
10096

10197
// NoContent sends a response with no body and a status code.
102-
func (c *Context) NoContent(code int) *HTTPError {
98+
func (c *Context) NoContent(code int) error {
10399
c.Response.WriteHeader(code)
104100
return nil
105101
}
106102

107103
// Error invokes the registered HTTP error handler.
108-
func (c *Context) Error(he *HTTPError) {
109-
c.echo.httpErrorHandler(he, c)
104+
func (c *Context) Error(err error) {
105+
c.echo.httpErrorHandler(err, c)
110106
}
111107

112108
// Get retrieves data from the context.

context_test.go

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,14 @@ type (
1616
}
1717
)
1818

19-
func (t *Template) Render(w io.Writer, name string, data interface{}) *HTTPError {
20-
if err := t.templates.ExecuteTemplate(w, name, data); err != nil {
21-
return &HTTPError{Error: err}
22-
}
23-
return nil
19+
func (t *Template) Render(w io.Writer, name string, data interface{}) error {
20+
return t.templates.ExecuteTemplate(w, name, data)
2421
}
2522

2623
func TestContext(t *testing.T) {
2724
b, _ := json.Marshal(u1)
2825
r, _ := http.NewRequest(POST, "/users/1", bytes.NewReader(b))
29-
c := NewContext(r, &Response{Writer: httptest.NewRecorder()}, New())
26+
c := NewContext(r, NewResponse(httptest.NewRecorder()), New())
3027

3128
//------
3229
// Bind

echo.go

Lines changed: 51 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"sync"
1515

1616
"github.com/mattn/go-colorable"
17+
"golang.org/x/net/websocket"
1718
)
1819

1920
type (
@@ -33,24 +34,23 @@ type (
3334
HTTPError struct {
3435
Code int
3536
Message string
36-
Error error
3737
}
3838
Middleware interface{}
3939
MiddlewareFunc func(HandlerFunc) HandlerFunc
4040
Handler interface{}
41-
HandlerFunc func(*Context) *HTTPError
41+
HandlerFunc func(*Context) error
4242

4343
// HTTPErrorHandler is a centralized HTTP error handler.
44-
HTTPErrorHandler func(*HTTPError, *Context)
44+
HTTPErrorHandler func(error, *Context)
4545

46-
BindFunc func(*http.Request, interface{}) *HTTPError
46+
BindFunc func(*http.Request, interface{}) error
4747

4848
// Renderer is the interface that wraps the Render method.
4949
//
5050
// Render renders the HTML template with given name and specified data.
5151
// It writes the output to w.
5252
Renderer interface {
53-
Render(w io.Writer, name string, data interface{}) *HTTPError
53+
Render(w io.Writer, name string, data interface{}) error
5454
}
5555
)
5656

@@ -120,6 +120,10 @@ var (
120120
RendererNotRegistered = errors.New("echo ⇒ renderer not registered")
121121
)
122122

123+
func (e *HTTPError) Error() string {
124+
return e.Message
125+
}
126+
123127
// New creates an Echo instance.
124128
func New() (e *Echo) {
125129
e = &Echo{
@@ -135,33 +139,30 @@ func New() (e *Echo) {
135139
//----------
136140

137141
e.SetMaxParam(5)
138-
e.notFoundHandler = func(c *Context) *HTTPError {
142+
e.notFoundHandler = func(c *Context) error {
139143
return &HTTPError{Code: http.StatusNotFound}
140144
}
141-
e.SetHTTPErrorHandler(func(he *HTTPError, c *Context) {
142-
if he.Code == 0 {
143-
he.Code = http.StatusInternalServerError
144-
}
145-
if he.Message == "" {
146-
he.Message = http.StatusText(he.Code)
145+
e.SetHTTPErrorHandler(func(err error, c *Context) {
146+
code := http.StatusInternalServerError
147+
msg := http.StatusText(code)
148+
if he, ok := err.(*HTTPError); ok {
149+
code = he.Code
150+
msg = he.Message
147151
}
148-
if e.debug && he.Error != nil {
149-
he.Message = he.Error.Error()
152+
if e.Debug() {
153+
msg = err.Error()
150154
}
151-
http.Error(c.Response, he.Message, he.Code)
155+
http.Error(c.Response, msg, code)
152156
})
153-
e.SetBinder(func(r *http.Request, v interface{}) *HTTPError {
157+
e.SetBinder(func(r *http.Request, v interface{}) error {
154158
ct := r.Header.Get(ContentType)
155159
err := UnsupportedMediaType
156160
if strings.HasPrefix(ct, ApplicationJSON) {
157161
err = json.NewDecoder(r.Body).Decode(v)
158162
} else if strings.HasPrefix(ct, ApplicationForm) {
159163
err = nil
160164
}
161-
if err != nil {
162-
return &HTTPError{Error: err}
163-
}
164-
return nil
165+
return err
165166
})
166167
return
167168
}
@@ -261,6 +262,21 @@ func (e *Echo) Trace(path string, h Handler) {
261262
e.add(TRACE, path, h)
262263
}
263264

265+
// WebSocket adds a WebSocket route > handler to the router.
266+
func (e *Echo) WebSocket(path string, h HandlerFunc) {
267+
e.Get(path, func(c *Context) *HTTPError {
268+
wss := websocket.Server{
269+
Handler: func(ws *websocket.Conn) {
270+
c.Socket = ws
271+
c.Response.status = http.StatusSwitchingProtocols
272+
h(c)
273+
},
274+
}
275+
wss.ServeHTTP(c.Response.writer, c.Request)
276+
return nil
277+
})
278+
}
279+
264280
func (e *Echo) add(method, path string, h Handler) {
265281
key := runtime.FuncForPC(reflect.ValueOf(h).Pointer()).Name()
266282
e.uris[key] = path
@@ -280,15 +296,15 @@ func (e *Echo) Favicon(file string) {
280296
// Static serves static files.
281297
func (e *Echo) Static(path, root string) {
282298
fs := http.StripPrefix(path, http.FileServer(http.Dir(root)))
283-
e.Get(path+"*", func(c *Context) *HTTPError {
299+
e.Get(path+"*", func(c *Context) error {
284300
fs.ServeHTTP(c.Response, c.Request)
285301
return nil
286302
})
287303
}
288304

289305
// ServeFile serves a file.
290306
func (e *Echo) ServeFile(path, file string) {
291-
e.Get(path, func(c *Context) *HTTPError {
307+
e.Get(path, func(c *Context) error {
292308
http.ServeFile(c.Response, c.Request, file)
293309
return nil
294310
})
@@ -376,16 +392,16 @@ func wrapMiddleware(m Middleware) MiddlewareFunc {
376392
return m
377393
case HandlerFunc:
378394
return wrapHandlerFuncMW(m)
379-
case func(*Context) *HTTPError:
395+
case func(*Context) error:
380396
return wrapHandlerFuncMW(m)
381397
case func(http.Handler) http.Handler:
382398
return func(h HandlerFunc) HandlerFunc {
383-
return func(c *Context) (he *HTTPError) {
399+
return func(c *Context) (err error) {
384400
m(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
385-
c.Response.Writer = w
401+
c.Response.writer = w
386402
c.Request = r
387-
he = h(c)
388-
})).ServeHTTP(c.Response.Writer, c.Request)
403+
err = h(c)
404+
})).ServeHTTP(c.Response.writer, c.Request)
389405
return
390406
}
391407
}
@@ -403,9 +419,9 @@ func wrapMiddleware(m Middleware) MiddlewareFunc {
403419
// Wraps HandlerFunc middleware
404420
func wrapHandlerFuncMW(m HandlerFunc) MiddlewareFunc {
405421
return func(h HandlerFunc) HandlerFunc {
406-
return func(c *Context) *HTTPError {
407-
if he := m(c); he != nil {
408-
return he
422+
return func(c *Context) error {
423+
if err := m(c); err != nil {
424+
return err
409425
}
410426
return h(c)
411427
}
@@ -415,9 +431,9 @@ func wrapHandlerFuncMW(m HandlerFunc) MiddlewareFunc {
415431
// Wraps http.HandlerFunc middleware
416432
func wrapHTTPHandlerFuncMW(m http.HandlerFunc) MiddlewareFunc {
417433
return func(h HandlerFunc) HandlerFunc {
418-
return func(c *Context) *HTTPError {
434+
return func(c *Context) error {
419435
if !c.Response.committed {
420-
m.ServeHTTP(c.Response.Writer, c.Request)
436+
m.ServeHTTP(c.Response.writer, c.Request)
421437
}
422438
return h(c)
423439
}
@@ -429,15 +445,15 @@ func wrapHandler(h Handler) HandlerFunc {
429445
switch h := h.(type) {
430446
case HandlerFunc:
431447
return h
432-
case func(*Context) *HTTPError:
448+
case func(*Context) error:
433449
return h
434450
case http.Handler, http.HandlerFunc:
435-
return func(c *Context) *HTTPError {
451+
return func(c *Context) error {
436452
h.(http.Handler).ServeHTTP(c.Response, c.Request)
437453
return nil
438454
}
439455
case func(http.ResponseWriter, *http.Request):
440-
return func(c *Context) *HTTPError {
456+
return func(c *Context) error {
441457
h(c.Response, c.Request)
442458
return nil
443459
}

0 commit comments

Comments
 (0)