Skip to content

Commit

Permalink
enabled validator, updated docs, fixed labstack#298, fixed labstack#438
Browse files Browse the repository at this point in the history
…, fixed labstack#305

Signed-off-by: Vishal Rana <[email protected]>
  • Loading branch information
vishr committed Dec 13, 2016
1 parent 70b5cfb commit 01334bc
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 37 deletions.
13 changes: 12 additions & 1 deletion context.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,12 @@ type (
// does it based on Content-Type header.
Bind(i interface{}) error

// Validate validates provided `i`. It is usually called after `Context#Bind()`.
// Validator must be registered using `Echo#Validator`.
Validate(i interface{}) error

// Render renders a template with data and sends a text/html response with status
// code. Templates can be registered using `Echo.Renderer`.
// code. Renderer must be registered using `Echo.Renderer`.
Render(code int, name string, data interface{}) error

// HTML sends an HTTP response with status code.
Expand Down Expand Up @@ -350,6 +354,13 @@ func (c *context) Bind(i interface{}) error {
return c.echo.Binder.Bind(i, c)
}

func (c *context) Validate(i interface{}) error {
if c.echo.Validator == nil {
return ErrValidatorNotRegistered
}
return c.echo.Validator.Validate(i)
}

func (c *context) Render(code int, name string, data interface{}) (err error) {
if c.echo.Renderer == nil {
return ErrRendererNotRegistered
Expand Down
4 changes: 3 additions & 1 deletion echo.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ type (
Debug bool
HTTPErrorHandler HTTPErrorHandler
Binder Binder
Validator Validator
Renderer Renderer
AutoTLSManager autocert.Manager
ShutdownTimeout time.Duration
Expand Down Expand Up @@ -102,7 +103,7 @@ type (

// Validator is the interface that wraps the Validate function.
Validator interface {
Validate() error
Validate(i interface{}) error
}

// Renderer is the interface that wraps the Render function.
Expand Down Expand Up @@ -217,6 +218,7 @@ var (
ErrUnauthorized = NewHTTPError(http.StatusUnauthorized)
ErrMethodNotAllowed = NewHTTPError(http.StatusMethodNotAllowed)
ErrStatusRequestEntityTooLarge = NewHTTPError(http.StatusRequestEntityTooLarge)
ErrValidatorNotRegistered = errors.New("validator not registered")
ErrRendererNotRegistered = errors.New("renderer not registered")
ErrInvalidRedirectCode = errors.New("invalid redirect status code")
ErrCookieNotFound = errors.New("cookie not found")
Expand Down
2 changes: 1 addition & 1 deletion website/content/guide/customization.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ You can set a custom HTTP error handler using `Echo#HTTPErrorHandler`.

## Debugging

`Echo#Debug` enables/disables debug mode.
`Echo#Debug` enable / disable debug mode.

## Logging

Expand Down
168 changes: 134 additions & 34 deletions website/content/guide/request.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,88 +7,188 @@ description = "Handling HTTP request in Echo"
weight = 6
+++

## Bind Request Body
## Bind Data

To bind request body into a provided Go type use `Context#Bind(interface{})`.
To bind request body into a Go type use `Context#Bind(i interface{})`.
The default binder supports decoding application/json, application/xml and
application/x-www-form-urlencoded payload based on Context-Type header.
application/x-www-form-urlencoded data based on the Context-Type header.

Example below binds the request payload into `User` struct based on tags:

```go
// User
User struct {
Name string `json:"name" form:"name" query:"name"`
Email string `json:"email" form:"email" query:"email"`
}
```

```go
// Handler
func(c echo.Context) (err error) {
u := new(User)
if err = c.Bind(u); err != nil {
return
}
return c.JSON(http.StatusOK, u)
}
```

### JSON Data

```sh
curl \
-X POST \
http://localhost:1323/users \
-H 'Content-Type: application/json' \
-d '{"name":"Joe","email":"joe@labstack"}'
```

### Form Data

```sh
curl \
-X POST \
http://localhost:1323/users \
-d 'name=Joe' \
-d '[email protected]'
```

### Query Parameters

```sh
curl \
-X GET \
http://localhost:1323/users\?name\=Joe\&email\=[email protected]
```

## Custom Binder

Custom binder can be registered using `Echo#Binder`.

*Example*

TODO
```go
type CustomBinder struct {}

func (cb *CustomBinder) Bind(i interface{}, c echo.Context) (err error) {
// You may use default binder
db := new(echo.DefaultBinder)
if err = db.Bind(i, c); err != echo.ErrUnsupportedMediaType {
return
}

// Define your custom implementation

return
}
```

> Custom binder can be registered via `Echo#SetBinder(Binder)`
## Retrieve Data

## Query Parameter
### Form Data

Query parameter can be retrieved by name using `Context#QueryParam(name string)`.
Form data can be retrieved by name using `Context#FormValue(name string)`.

*Example*

```go
e.GET("/users", func(c echo.Context) error {
name := c.QueryParam("name")
// Handler
func(c echo.Context) error {
name := c.FormValue("name")
return c.String(http.StatusOK, name)
})
}
```

```sh
$ curl -G -d "name=joe" http://localhost:1323/users
curl \
-X POST \
http://localhost:1323 \
-d 'name=Joe'
```

## Form Parameter
### Query Parameters

Form parameter can be retrieved by name using `Context#FormValue(name string)`.
Query parameters can be retrieved by name using `Context#QueryParam(name string)`.

*Example*

```go
e.POST("/users", func(c echo.Context) error {
name := c.FormValue("name")
// Handler
func(c echo.Context) error {
name := c.QueryParam("name")
return c.String(http.StatusOK, name)
})
```

```sh
$ curl -d "name=joe" http://localhost:1323/users
curl \
-X GET \
http://localhost:1323\?name\=Joe
```

## Path Parameter
### Path Parameters

Registered path parameter can be retrieved by name `Context#Param(name string) string`.
Registered path parameters can be retrieved by name using `Context#Param(name string) string`.

*Example*

```go
e.GET("/users/:name", func(c echo.Context) error {
// By name
name := c.Param("name")

return c.String(http.StatusOK, name)
})
```

```sh
$ curl http://localhost:1323/users/joe
$ curl http://localhost:1323/users/Joe
```

## Validate Data

## Handler Path
Echo doesn't have built-in data validation capabilities, however you can set a
custom validator using `Echo#Validator` and leverage third-party [libraries](https://github.com/avelino/awesome-go#validation).

`Context#Path()` returns the registered path for the handler, it can be used in the
middleware for logging purpose.

*Example*
Example below uses https://github.com/go-playground/validator framework for validation:

```go
e.Use(func(handler echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
println(c.Path())
return handler(c)
type (
User struct {
Name string `json:"name" validate:"required"`
Email string `json:"email" validate:"required,email"`
}
})

e.GET("/users/:name", func(c echo.Context) error) {
return c.String(http.StatusOK, name)
})
CustomValidator struct {
validator *validator.Validate
}
)

func (cv *CustomValidator) Validate(i interface{}) error {
return cv.validator.Struct(i)
}

func main() {
e := echo.New()
e.Validator = &CustomValidator{validator: validator.New()}
e.POST("/users", func(c echo.Context) (err error) {
u := new(User)
if err = c.Bind(u); err != nil {
return
}
if err = c.Validate(u); err != nil {
return
}
return c.JSON(http.StatusOK, u)
})
e.Logger.Fatal(e.Start(":1323"))
}
```

```sh
curl \
-X POST \
http://localhost:1323/users \
-H 'Content-Type: application/json' \
-d '{"name":"Joe","email":"joe@invalid-domain"}'
{"message":"Key: 'User.Email' Error:Field validation for 'Email' failed on the 'email' tag"}
```

0 comments on commit 01334bc

Please sign in to comment.