Skip to content

Commit

Permalink
Changed Context to interface
Browse files Browse the repository at this point in the history
Signed-off-by: Vishal Rana <vr@labstack.com>
  • Loading branch information
lestrrat authored and vishr committed Sep 13, 2015
1 parent 0c6c82f commit 4b49195
Show file tree
Hide file tree
Showing 32 changed files with 263 additions and 174 deletions.
4 changes: 2 additions & 2 deletions README.md
Expand Up @@ -9,14 +9,14 @@ A fast and unfancy micro web framework for Golang.
- `echo.MiddlewareFunc`
- `func(echo.HandlerFunc) echo.HandlerFunc`
- `echo.HandlerFunc`
- `func(*echo.Context) error`
- `func(echo.Context) error`
- `func(http.Handler) http.Handler`
- `http.Handler`
- `http.HandlerFunc`
- `func(http.ResponseWriter, *http.Request)`
- Extensible handler, supports:
- `echo.HandlerFunc`
- `func(*echo.Context) error`
- `func(echo.Context) error`
- `http.Handler`
- `http.HandlerFunc`
- `func(http.ResponseWriter, *http.Request)`
Expand Down
101 changes: 78 additions & 23 deletions context.go
Expand Up @@ -15,7 +15,32 @@ import (
type (
// Context represents context for the current request. It holds request and
// response objects, path parameters, data and registered handler.
Context struct {
Context interface {
Bind(interface{}) error
Error(err error)
Form(string) string
Get(string) interface{}
JSON(int, interface{}) error
NoContent(int) error
P(int) string
Param(string) string
PathParameters() []string
PathParameterValues() []string
Render(int, string, interface{}) error
Request() *http.Request
Reset(*http.Request, http.ResponseWriter, *Echo)
Response() *Response
Socket() *websocket.Conn
Set(string, interface{})
SetPathParameters([]string)
SetPathParameterValue(int, string)
SetRequest(*http.Request)
SetSocket(*websocket.Conn)
String(int, string, ...interface{}) error
}


context struct {
request *http.Request
response *Response
socket *websocket.Conn
Expand All @@ -29,8 +54,8 @@ type (
)

// NewContext creates a Context object.
func NewContext(req *http.Request, res *Response, e *Echo) *Context {
return &Context{
func NewContext(req *http.Request, res *Response, e *Echo) Context {
return &context{
request: req,
response: res,
echo: e,
Expand All @@ -40,22 +65,52 @@ func NewContext(req *http.Request, res *Response, e *Echo) *Context {
}

// Request returns *http.Request.
func (c *Context) Request() *http.Request {
func (c *context) Request() *http.Request {
return c.request
}

// SetRequest sets *http.Request.
func (c *context) SetRequest(r *http.Request) {
c.request = r
}

// Response returns *Response.
func (c *Context) Response() *Response {
func (c *context) Response() *Response {
return c.response
}

// Socket returns *websocket.Conn.
func (c *Context) Socket() *websocket.Conn {
func (c *context) Socket() *websocket.Conn {
return c.socket
}

// SetSocket sets *websocket.Conn.
func (c *context) SetSocket(sock *websocket.Conn) {
c.socket = sock
}

// SetPathParameters sets the path parameter names
func (c *context) SetPathParameters(l []string) {
c.pnames = l
}

// SetPathParameters sets the path parameter names
func (c *context) SetPathParameterValue(n int, s string) {
c.pvalues[n] = s
}

// PathParameters returns all of the path parameter names
func (c *context) PathParameters() []string {
return c.pnames
}

// PathParameterValues returns all of the path parameter values
func (c *context) PathParameterValues() []string {
return c.pvalues
}

// P returns path parameter by index.
func (c *Context) P(i int) (value string) {
func (c *context) P(i int) (value string) {
l := len(c.pnames)
if i < l {
value = c.pvalues[i]
Expand All @@ -64,7 +119,7 @@ func (c *Context) P(i int) (value string) {
}

// Param returns path parameter by name.
func (c *Context) Param(name string) (value string) {
func (c *context) Param(name string) (value string) {
l := len(c.pnames)
for i, n := range c.pnames {
if n == name && i < l {
Expand All @@ -76,25 +131,25 @@ func (c *Context) Param(name string) (value string) {
}

// Query returns query parameter by name.
func (c *Context) Query(name string) string {
func (c *context) Query(name string) string {
if c.query == nil {
c.query = c.request.URL.Query()
}
return c.query.Get(name)
}

// Form returns form parameter by name.
func (c *Context) Form(name string) string {
func (c *context) Form(name string) string {
return c.request.FormValue(name)
}

// Get retrieves data from the context.
func (c *Context) Get(key string) interface{} {
func (c *context) Get(key string) interface{} {
return c.store[key]
}

// Set saves data in the context.
func (c *Context) Set(key string, val interface{}) {
func (c *context) Set(key string, val interface{}) {
if c.store == nil {
c.store = make(store)
}
Expand All @@ -103,13 +158,13 @@ func (c *Context) Set(key string, val interface{}) {

// Bind binds the request body into specified type `i`. The default binder does
// it based on Content-Type header.
func (c *Context) Bind(i interface{}) error {
func (c *context) Bind(i interface{}) error {
return c.echo.binder.Bind(c.request, i)
}

// Render renders a template with data and sends a text/html response with status
// code. Templates can be registered using `Echo.SetRenderer()`.
func (c *Context) Render(code int, name string, data interface{}) error {
func (c *context) Render(code int, name string, data interface{}) error {
if c.echo.renderer == nil {
return RendererNotRegistered
}
Expand All @@ -120,7 +175,7 @@ func (c *Context) Render(code int, name string, data interface{}) error {

// HTML formats according to a format specifier and sends HTML response with
// status code.
func (c *Context) HTML(code int, format string, a ...interface{}) (err error) {
func (c *context) HTML(code int, format string, a ...interface{}) (err error) {
c.response.Header().Set(ContentType, TextHTMLCharsetUTF8)
c.response.WriteHeader(code)
_, err = fmt.Fprintf(c.response, format, a...)
Expand All @@ -129,23 +184,23 @@ func (c *Context) HTML(code int, format string, a ...interface{}) (err error) {

// String formats according to a format specifier and sends text response with status
// code.
func (c *Context) String(code int, format string, a ...interface{}) (err error) {
func (c *context) String(code int, format string, a ...interface{}) (err error) {
c.response.Header().Set(ContentType, TextPlain)
c.response.WriteHeader(code)
_, err = fmt.Fprintf(c.response, format, a...)
return
}

// JSON sends a JSON response with status code.
func (c *Context) JSON(code int, i interface{}) error {
func (c *context) JSON(code int, i interface{}) error {
c.response.Header().Set(ContentType, ApplicationJSONCharsetUTF8)
c.response.WriteHeader(code)
return json.NewEncoder(c.response).Encode(i)
}

// JSONP sends a JSONP response with status code. It uses `callback` to construct
// the JSONP payload.
func (c *Context) JSONP(code int, callback string, i interface{}) (err error) {
func (c *context) JSONP(code int, callback string, i interface{}) (err error) {
c.response.Header().Set(ContentType, ApplicationJavaScriptCharsetUTF8)
c.response.WriteHeader(code)
c.response.Write([]byte(callback + "("))
Expand All @@ -156,21 +211,21 @@ func (c *Context) JSONP(code int, callback string, i interface{}) (err error) {
}

// XML sends an XML response with status code.
func (c *Context) XML(code int, i interface{}) error {
func (c *context) XML(code int, i interface{}) error {
c.response.Header().Set(ContentType, ApplicationXMLCharsetUTF8)
c.response.WriteHeader(code)
c.response.Write([]byte(xml.Header))
return xml.NewEncoder(c.response).Encode(i)
}

// NoContent sends a response with no body and a status code.
func (c *Context) NoContent(code int) error {
func (c *context) NoContent(code int) error {
c.response.WriteHeader(code)
return nil
}

// Redirect redirects the request using http.Redirect with status code.
func (c *Context) Redirect(code int, url string) error {
func (c *context) Redirect(code int, url string) error {
if code < http.StatusMultipleChoices || code > http.StatusTemporaryRedirect {
return InvalidRedirectCode
}
Expand All @@ -179,11 +234,11 @@ func (c *Context) Redirect(code int, url string) error {
}

// Error invokes the registered HTTP error handler. Generally used by middleware.
func (c *Context) Error(err error) {
func (c *context) Error(err error) {
c.echo.httpErrorHandler(err, c)
}

func (c *Context) reset(r *http.Request, w http.ResponseWriter, e *Echo) {
func (c *context) Reset(r *http.Request, w http.ResponseWriter, e *Echo) {
c.request = r
c.response.reset(w)
c.query = nil
Expand Down
30 changes: 15 additions & 15 deletions context_test.go
Expand Up @@ -32,7 +32,7 @@ func TestContext(t *testing.T) {

req, _ := http.NewRequest(POST, "/", strings.NewReader(userJSON))
rec := httptest.NewRecorder()
c := NewContext(req, NewResponse(rec), New())
c := NewContext(req, NewResponse(rec), New()).(*context)

// Request
assert.NotNil(t, c.Request())
Expand Down Expand Up @@ -90,7 +90,7 @@ func TestContext(t *testing.T) {
// JSON
req.Header.Set(Accept, ApplicationJSON)
rec = httptest.NewRecorder()
c = NewContext(req, NewResponse(rec), New())
c = NewContext(req, NewResponse(rec), New()).(*context)
err = c.JSON(http.StatusOK, user{"1", "Joe"})
if assert.NoError(t, err) {
assert.Equal(t, http.StatusOK, rec.Code)
Expand All @@ -101,7 +101,7 @@ func TestContext(t *testing.T) {
// JSONP
req.Header.Set(Accept, ApplicationJavaScript)
rec = httptest.NewRecorder()
c = NewContext(req, NewResponse(rec), New())
c = NewContext(req, NewResponse(rec), New()).(*context)
callback := "callback"
err = c.JSONP(http.StatusOK, callback, user{"1", "Joe"})
if assert.NoError(t, err) {
Expand All @@ -113,7 +113,7 @@ func TestContext(t *testing.T) {
// XML
req.Header.Set(Accept, ApplicationXML)
rec = httptest.NewRecorder()
c = NewContext(req, NewResponse(rec), New())
c = NewContext(req, NewResponse(rec), New()).(*context)
err = c.XML(http.StatusOK, user{"1", "Joe"})
if assert.NoError(t, err) {
assert.Equal(t, http.StatusOK, rec.Code)
Expand All @@ -124,7 +124,7 @@ func TestContext(t *testing.T) {
// String
req.Header.Set(Accept, TextPlain)
rec = httptest.NewRecorder()
c = NewContext(req, NewResponse(rec), New())
c = NewContext(req, NewResponse(rec), New()).(*context)
err = c.String(http.StatusOK, "Hello, World!")
if assert.NoError(t, err) {
assert.Equal(t, http.StatusOK, rec.Code)
Expand All @@ -135,7 +135,7 @@ func TestContext(t *testing.T) {
// HTML
req.Header.Set(Accept, TextHTML)
rec = httptest.NewRecorder()
c = NewContext(req, NewResponse(rec), New())
c = NewContext(req, NewResponse(rec), New()).(*context)
err = c.HTML(http.StatusOK, "Hello, <strong>World!</strong>")
if assert.NoError(t, err) {
assert.Equal(t, http.StatusOK, rec.Code)
Expand All @@ -145,23 +145,23 @@ func TestContext(t *testing.T) {

// NoContent
rec = httptest.NewRecorder()
c = NewContext(req, NewResponse(rec), New())
c = NewContext(req, NewResponse(rec), New()).(*context)
c.NoContent(http.StatusOK)
assert.Equal(t, http.StatusOK, c.response.status)
assert.Equal(t, http.StatusOK, c.Response().status)

// Redirect
rec = httptest.NewRecorder()
c = NewContext(req, NewResponse(rec), New())
c = NewContext(req, NewResponse(rec), New()).(*context)
assert.Equal(t, nil, c.Redirect(http.StatusMovedPermanently, "http://labstack.github.io/echo"))

// Error
rec = httptest.NewRecorder()
c = NewContext(req, NewResponse(rec), New())
c = NewContext(req, NewResponse(rec), New()).(*context)
c.Error(errors.New("error"))
assert.Equal(t, http.StatusInternalServerError, c.response.status)

// reset
c.reset(req, NewResponse(httptest.NewRecorder()), New())
c.Reset(req, NewResponse(httptest.NewRecorder()), New())
}

func TestContextQuery(t *testing.T) {
Expand All @@ -173,7 +173,7 @@ func TestContextQuery(t *testing.T) {
assert.NoError(t, err)
req.URL.RawQuery = q.Encode()

c := NewContext(req, nil, New())
c := NewContext(req, nil, New()).(*context)
assert.Equal(t, "joe", c.Query("name"))
assert.Equal(t, "joe@labstack.com", c.Query("email"))

Expand All @@ -188,13 +188,13 @@ func TestContextForm(t *testing.T) {
assert.NoError(t, err)
req.Header.Add(ContentType, ApplicationForm)

c := NewContext(req, nil, New())
c := NewContext(req, nil, New()).(*context)
assert.Equal(t, "joe", c.Form("name"))
assert.Equal(t, "joe@labstack.com", c.Form("email"))
}

func testBind(t *testing.T, c *Context, ct string) {
c.request.Header.Set(ContentType, ct)
func testBind(t *testing.T, c Context, ct string) {
c.Request().Header.Set(ContentType, ct)
u := new(user)
err := c.Bind(u)
if ct == "" {
Expand Down

0 comments on commit 4b49195

Please sign in to comment.