<commit_before>+++
title = "Binding Request Data"
description = "Binding request data"
[menu.main]
  name = "Binding"
  parent = "guide"
+++

Parsing request data is a crucial part of a web application.  In Echo this is done with a process called _binding_. This is done with information passed by the client in the following parts of an HTTP request:

* URL Path parameter
* URL Query parameter
* Header
* Request body

Echo provides different ways to perform binding, each described in the sections below.

## Struct Tag Binding

With struct binding you define a Go struct with tags specifying the data source and corresponding key. In your request handler you simply call `Context#Bind(i interface{})` with a pointer to your struct. The tags tell the binder everything it needs to know to load data from the request.

In this example a struct type `User` tells the binder to bind the query string parameter `id` to its string field `ID`:

```go
type User struct {
  ID string `query:"id"`
}

// in the handler for /users?id=<userID>
var user User
err := c.Bind(&user); if err != nil {
    return c.String(http.StatusBadRequest, "bad request")
}
```

### Data Sources

Echo supports the following tags specifying data sources:

* `query` - query parameter
* `param` - path parameter (also called route)
* `header` - header parameter
* `json` - request body. Uses builtin Go [json](https://golang.org/pkg/encoding/json/) package for unmarshalling.
* `xml` - request body. Uses builtin Go [xml](https://golang.org/pkg/encoding/xml/) package for unmarshalling.
* `form` - form data. Values are taken from query and request body. Uses Go standard library form parsing.

### Data Types

When decoding the request body, the following data types are supported as specified by the `Content-Type` header:

* `application/json`
* `application/xml`
* `application/x-www-form-urlencoded`

When binding path parameter, query parameter, header, or form data, tags must be explicitly set on each struct field. However, JSON and XML binding is done on the struct field name if the tag is omitted. This is according to the behaviour of [Go's json package](https://pkg.go.dev/encoding/json#Unmarshal).

For form data, Echo uses Go standard library form parsing. This parses form data from both the request URL and body if content type is not `MIMEMultipartForm`. See documentation for [non-MIMEMultipartForm](https://golang.org/pkg/net/http/#Request.ParseForm)and [MIMEMultipartForm](https://golang.org/pkg/net/http/#Request.ParseMultipartForm)

### Multiple Sources

It is possible to specify multiple sources on the same field. In this case request data is bound in this order:

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

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

Note that binding at each stage will overwrite data bound in a previous stage. This means if your JSON request contains the query param `name=query` and body `{"name": "body"}` then the result will be `User{Name: "body"}`.

### Direct Source

It is also possible to bind data directly from a specific source:
  
Request body:
```go
err := (&DefaultBinder{}).BindBody(c, &payload)
```

Query parameters:
```go
err := (&DefaultBinder{}).BindQueryParams(c, &payload)
```

Path parameters:
```go
err := (&DefaultBinder{}).BindPathParams(c, &payload)
```

Header parameters:
```go
err := (&DefaultBinder{}).BindHeaders(c, &payload)
```

Note that headers is not one of the included sources with `Context#Bind`. The only way to bind header data is by calling `BindHeaders` directly.

### Security

To keep your application secure, avoid passing bound structs directly to other methods if these structs contain fields that should not be bindable. It is advisable to have a separate struct for binding and map it explicitly to your business struct.

Consider what will happen if your bound struct has an Exported field `IsAdmin bool` and the request body contains `{IsAdmin: true, Name: "hacker"}`.

### Example

In this example we define a `User` struct type with field tags to bind from `json`, `form`, or `query` request data:

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

type UserDTO struct {
  Name  string
  Email string
  IsAdmin: bool
}
```

And a handler at the POST `/users` route binds request data to the struct:

```go
e.POST("/users", func(c echo.Context) (err error) {
  u := new(User)
  if err = c.Bind(u); err != nil {
    return c.String(http.StatusBadRequest, "bad request")
  }

  // Load into separate struct for security
  user := UserDTO{
    Name: u.Name,
    Email: u.Email,
    IsAdmin: false // avoids exposing field that should not be bound
  }

  executeSomeBusinessLogic(user)
  
  return c.JSON(http.StatusOK, u)
})<commit_msg>chore: fix typo in `UserDTO` type<commit_after>+++
title = "Binding Request Data"
description = "Binding request data"
[menu.main]
  name = "Binding"
  parent = "guide"
+++

Parsing request data is a crucial part of a web application.  In Echo this is done with a process called _binding_. This is done with information passed by the client in the following parts of an HTTP request:

* URL Path parameter
* URL Query parameter
* Header
* Request body

Echo provides different ways to perform binding, each described in the sections below.

## Struct Tag Binding

With struct binding you define a Go struct with tags specifying the data source and corresponding key. In your request handler you simply call `Context#Bind(i interface{})` with a pointer to your struct. The tags tell the binder everything it needs to know to load data from the request.

In this example a struct type `User` tells the binder to bind the query string parameter `id` to its string field `ID`:

```go
type User struct {
  ID string `query:"id"`
}

// in the handler for /users?id=<userID>
var user User
err := c.Bind(&user); if err != nil {
    return c.String(http.StatusBadRequest, "bad request")
}
```

### Data Sources

Echo supports the following tags specifying data sources:

* `query` - query parameter
* `param` - path parameter (also called route)
* `header` - header parameter
* `json` - request body. Uses builtin Go [json](https://golang.org/pkg/encoding/json/) package for unmarshalling.
* `xml` - request body. Uses builtin Go [xml](https://golang.org/pkg/encoding/xml/) package for unmarshalling.
* `form` - form data. Values are taken from query and request body. Uses Go standard library form parsing.

### Data Types

When decoding the request body, the following data types are supported as specified by the `Content-Type` header:

* `application/json`
* `application/xml`
* `application/x-www-form-urlencoded`

When binding path parameter, query parameter, header, or form data, tags must be explicitly set on each struct field. However, JSON and XML binding is done on the struct field name if the tag is omitted. This is according to the behaviour of [Go's json package](https://pkg.go.dev/encoding/json#Unmarshal).

For form data, Echo uses Go standard library form parsing. This parses form data from both the request URL and body if content type is not `MIMEMultipartForm`. See documentation for [non-MIMEMultipartForm](https://golang.org/pkg/net/http/#Request.ParseForm)and [MIMEMultipartForm](https://golang.org/pkg/net/http/#Request.ParseMultipartForm)

### Multiple Sources

It is possible to specify multiple sources on the same field. In this case request data is bound in this order:

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

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

Note that binding at each stage will overwrite data bound in a previous stage. This means if your JSON request contains the query param `name=query` and body `{"name": "body"}` then the result will be `User{Name: "body"}`.

### Direct Source

It is also possible to bind data directly from a specific source:
  
Request body:
```go
err := (&DefaultBinder{}).BindBody(c, &payload)
```

Query parameters:
```go
err := (&DefaultBinder{}).BindQueryParams(c, &payload)
```

Path parameters:
```go
err := (&DefaultBinder{}).BindPathParams(c, &payload)
```

Header parameters:
```go
err := (&DefaultBinder{}).BindHeaders(c, &payload)
```

Note that headers is not one of the included sources with `Context#Bind`. The only way to bind header data is by calling `BindHeaders` directly.

### Security

To keep your application secure, avoid passing bound structs directly to other methods if these structs contain fields that should not be bindable. It is advisable to have a separate struct for binding and map it explicitly to your business struct.

Consider what will happen if your bound struct has an Exported field `IsAdmin bool` and the request body contains `{IsAdmin: true, Name: "hacker"}`.

### Example

In this example we define a `User` struct type with field tags to bind from `json`, `form`, or `query` request data:

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

type UserDTO struct {
  Name    string
  Email   string
  IsAdmin bool
}
```

And a handler at the POST `/users` route binds request data to the struct:

```go
e.POST("/users", func(c echo.Context) (err error) {
  u := new(User)
  if err = c.Bind(u); err != nil {
    return c.String(http.StatusBadRequest, "bad request")
  }

  // Load into separate struct for security
  user := UserDTO{
    Name: u.Name,
    Email: u.Email,
    IsAdmin: false // avoids exposing field that should not be bound
  }

  executeSomeBusinessLogic(user)
  
  return c.JSON(http.StatusOK, u)
})
{'fraction_non_alphanumeric': 0.10235498012029769, 'fraction_numerical': 0.0006116831481292691, 'mean_word_length': 4.337323177366703, 'pattern_counts': {'":': 2, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 10, 'lorem ipsum': 0, 'www.': 2, 'xml': 10}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1986779', 'n_tokens_mistral': 2816, 'n_tokens_neox': 2718, 'n_words': 1289}