diff --git a/bind.go b/bind.go index 08d398916..2caf91c8b 100644 --- a/bind.go +++ b/bind.go @@ -97,6 +97,14 @@ func (b *DefaultBinder) BindBody(c Context, i interface{}) (err error) { return nil } +// BindHeaders binds HTTP headers to a bindable object +func (b *DefaultBinder) BindHeaders(c Context, i interface{}) error { + if err := b.bindData(i, c.Request().Header, "header"); err != nil { + return NewHTTPError(http.StatusBadRequest, err.Error()).SetInternal(err) + } + return nil +} + // Bind implements the `Binder#Bind` function. // Binding is done in following order: 1) path params; 2) query params; 3) request body. Each step COULD override previous // step binded values. For single source binding use their own methods BindBody, BindQueryParams, BindPathParams. @@ -134,7 +142,7 @@ func (b *DefaultBinder) bindData(destination interface{}, data map[string][]stri // !struct if typ.Kind() != reflect.Struct { - if tag == "param" || tag == "query" { + if tag == "param" || tag == "query" || tag == "header" { // incompatible type, data is probably to be found in the body return nil } diff --git a/bind_test.go b/bind_test.go index 73398034e..b78b0abc5 100644 --- a/bind_test.go +++ b/bind_test.go @@ -266,6 +266,37 @@ func TestBindQueryParamsCaseSensitivePrioritized(t *testing.T) { } } +func TestBindHeaderParam(t *testing.T) { + e := New() + req := httptest.NewRequest(http.MethodGet, "/", nil) + req.Header.Set("Name", "Jon Doe") + req.Header.Set("Id", "2") + rec := httptest.NewRecorder() + c := e.NewContext(req, rec) + u := new(user) + err := (&DefaultBinder{}).BindHeaders(c, u) + if assert.NoError(t, err) { + assert.Equal(t, 2, u.ID) + assert.Equal(t, "Jon Doe", u.Name) + } +} + +func TestBindHeaderParamBadType(t *testing.T) { + e := New() + req := httptest.NewRequest(http.MethodGet, "/", nil) + req.Header.Set("Id", "salamander") + rec := httptest.NewRecorder() + c := e.NewContext(req, rec) + u := new(user) + err := (&DefaultBinder{}).BindHeaders(c, u) + assert.Error(t, err) + + httpErr, ok := err.(*HTTPError) + if assert.True(t, ok) { + assert.Equal(t, http.StatusBadRequest, httpErr.Code) + } +} + func TestBindUnmarshalParam(t *testing.T) { e := New() req := httptest.NewRequest(http.MethodGet, "/?ts=2016-12-06T19:09:05Z&sa=one,two,three&ta=2016-12-06T19:09:05Z&ta=2016-12-06T19:09:05Z&ST=baz", nil) diff --git a/echo_test.go b/echo_test.go index ba498831b..e5bd371dd 100644 --- a/echo_test.go +++ b/echo_test.go @@ -24,8 +24,8 @@ import ( type ( user struct { - ID int `json:"id" xml:"id" form:"id" query:"id" param:"id"` - Name string `json:"name" xml:"name" form:"name" query:"name" param:"name"` + ID int `json:"id" xml:"id" form:"id" query:"id" param:"id" header:"id"` + Name string `json:"name" xml:"name" form:"name" query:"name" param:"name" header:"name"` } )