Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Docs for #1736 fluent binder #172

Merged
merged 4 commits into from
Feb 2, 2021
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 83 additions & 3 deletions website/content/guide/request.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,100 @@ description = "Handling HTTP request in Echo"
parent = "guide"
+++

## Bind Data
## Bind request data with bind functions

Echo provides following method to bind data from different sources (path params, query params, request body) to structure
Following functions provide handful of methods for binding to Go native types from request query or path parameters.

* `echo.QueryParamsBinder(c)` - binds query parameters (source URL)
* `echo.PathParamsBinder(c)` - binds path parameters (source URL)
* `echo.FormFieldBinder(c)` - binds form fields (source URL + body). See also [Request.ParseForm](https://golang.org/pkg/net/http/#Request.ParseForm).

```go
// url = "/api/search?active=true&id=1&id=2&id=3&length=25"
var opts struct {
IDs []int64
Active bool
}
length := int64(50) // default length is 50

// creates query params binder that stops binding at first error
err := echo.QueryParamsBinder(c).
Int64("length", &length).
Int64s("ids", &opts.IDs).
Bool("active", &opts.Active).
BindError() // returns first binding error
```

### Methods
`FailFast` flags binder to stop binding after first bind error during binder call chain. Enabled by default.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think FailFast should include the () to be consistent

`BindError()` returns first bind error from binder and resets errors in binder. Useful along with `FailFast()` method
to do binding and returns on first problem
`BindErrors()` returns all bind errors from binder and resets errors in binder.

### Supported types

Types that are supported:

* bool
* float32
* float64
* int
* int8
* int16
* int32
* int64
* uint
* uint8/byte (does not support `bytes()`. Use BindUnmarshaler/CustomFunc to convert value from base64 etc to []byte{})
* uint16
* uint32
* uint64
* string
* time
* duration
* BindUnmarshaler() interface
* UnixTime() - converts unix time (integer) to time.Time
* CustomFunc() - callback function for your custom conversion logic

For every supported type there are following methods:

* `<Type>("param", &destination)` - if parameter value exists then binds it to given destination of that type i.e `Int64(...)`.
* `Must<Type>("param", &destination)` - parameter value is required to exist, binds it to given destination of that type i.e `MustInt64(...)`.
* `<Type>s("param", &destination)` - (for slices) if parameter values exists then binds it to given destination of that type i.e `I`nt64s(...)`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here there is a extra ` after the I (`I`nt64s(...)`)

* `Must<Type>s("param", &destination)` - (for slices) parameter value is required to exist, binds it to given destination of that type i.e `MustInt64s(...)`.

for some slice types `BindWithDelimiter("param", &dest, ",")` supports slitting parameter values before type conversion is done
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo on slitting

i.e. URL `/api/search?id=1,2,3&id=1` can be bind to `[]int64{1,2,3,1}`

## Bind request data with struct tags

Echo provides following method to bind data from different sources (path params, query params, request body) to structure using
`Context#Bind(i interface{})` method.
The default binder supports decoding application/json, application/xml and
application/x-www-form-urlencoded data based on the Content-Type header.

Supported struct tags:
* `query` - source is request query parameters.
* `param` - source is route path parameter.
* `form` - source is form. Values are taken from query and request body. Uses Go standard library form parsing.
* `json` - source is request body. Uses Go [json](https://golang.org/pkg/encoding/json/) package fo unmarshalling.
* `xml` - source is request body. Uses Go [xml](https://golang.org/pkg/encoding/xml/) package fo unmarshalling.

```go
type User struct {
ID string `path:"id" query:"id" form:"id" json:"id" xml:"id"`
}
```

Request data is binded to the struct in given order:

1. Path parameters
2. Query parameters
2. Query parameters (only for GET/DELETE methods)
3. Request body

Notes:

* For `query`, `param`, `form` **only** fields **with** tags are binded.
* For `json` and `xml` can bind to *public* fields without tags but this is by their standard library implementation.
* Each step can overwrite binded fields from the previous step. This means if your json request has query param
`&name=query` and body is `{"name": "body"}` then the result will be `User{Name: "body"}`.
* To avoid security flaws try to avoid passing binded structs directly to other methods if
Expand Down Expand Up @@ -49,6 +128,7 @@ Notes:
}
```

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

```go
Expand Down