mirror of
				https://github.com/labstack/echo.git
				synced 2025-10-30 23:57:38 +02:00 
			
		
		
		
	| @@ -22,7 +22,7 @@ type ( | ||||
| 
 | ||||
| 	// BindUnmarshaler is the interface used to wrap the UnmarshalParam method. | ||||
| 	BindUnmarshaler interface { | ||||
| 		// UnmarshalParam decodes and assigns a value from an HTML form. | ||||
| 		// UnmarshalParam decodes and assigns a value from an form or query param. | ||||
| 		UnmarshalParam(src string) error | ||||
| 	} | ||||
| ) | ||||
| @@ -15,7 +15,7 @@ import ( | ||||
| ) | ||||
| 
 | ||||
| type ( | ||||
| 	binderTestStruct struct { | ||||
| 	bindTestStruct struct { | ||||
| 		I           int | ||||
| 		I8          int8 | ||||
| 		I16         int16 | ||||
| @@ -36,19 +36,16 @@ type ( | ||||
| 		Tptr        *Timestamp | ||||
| 	} | ||||
| 
 | ||||
| 	// Timestamp is a simple datatype which implements the Scanner interface | ||||
| 	// used for testing. | ||||
| 	Timestamp time.Time | ||||
| ) | ||||
| 
 | ||||
| // UnmarshalParam unmarshals a value from an HTML form into a Timestamp value | ||||
| func (t *Timestamp) UnmarshalParam(src string) error { | ||||
| 	ts, err := time.Parse(time.RFC3339, src) | ||||
| 	*t = Timestamp(ts) | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| func (t binderTestStruct) GetCantSet() string { | ||||
| func (t bindTestStruct) GetCantSet() string { | ||||
| 	return t.cantSet | ||||
| } | ||||
| 
 | ||||
| @@ -72,19 +69,19 @@ var values = map[string][]string{ | ||||
| 	"Tptr":    {"2016-12-06T19:09:05+01:00"}, | ||||
| } | ||||
| 
 | ||||
| func TestBinderJSON(t *testing.T) { | ||||
| 	testBinderOkay(t, strings.NewReader(userJSON), MIMEApplicationJSON) | ||||
| 	testBinderError(t, strings.NewReader(invalidContent), MIMEApplicationJSON) | ||||
| func TestBindJSON(t *testing.T) { | ||||
| 	testBindOkay(t, strings.NewReader(userJSON), MIMEApplicationJSON) | ||||
| 	testBindError(t, strings.NewReader(invalidContent), MIMEApplicationJSON) | ||||
| } | ||||
| 
 | ||||
| func TestBinderXML(t *testing.T) { | ||||
| 	testBinderOkay(t, strings.NewReader(userXML), MIMEApplicationXML) | ||||
| 	testBinderError(t, strings.NewReader(invalidContent), MIMEApplicationXML) | ||||
| func TestBindXML(t *testing.T) { | ||||
| 	testBindOkay(t, strings.NewReader(userXML), MIMEApplicationXML) | ||||
| 	testBindError(t, strings.NewReader(invalidContent), MIMEApplicationXML) | ||||
| } | ||||
| 
 | ||||
| func TestBinderForm(t *testing.T) { | ||||
| 	testBinderOkay(t, strings.NewReader(userForm), MIMEApplicationForm) | ||||
| 	testBinderError(t, nil, MIMEApplicationForm) | ||||
| func TestBindForm(t *testing.T) { | ||||
| 	testBindOkay(t, strings.NewReader(userForm), MIMEApplicationForm) | ||||
| 	testBindError(t, nil, MIMEApplicationForm) | ||||
| 	e := New() | ||||
| 	req, _ := http.NewRequest(POST, "/", strings.NewReader(userForm)) | ||||
| 	rec := httptest.NewRecorder() | ||||
| @@ -95,7 +92,7 @@ func TestBinderForm(t *testing.T) { | ||||
| 	assert.Error(t, err) | ||||
| } | ||||
| 
 | ||||
| func TestBinderQueryParams(t *testing.T) { | ||||
| func TestBindQueryParams(t *testing.T) { | ||||
| 	e := New() | ||||
| 	req, _ := http.NewRequest(GET, "/?id=1&name=Jon Snow", nil) | ||||
| 	rec := httptest.NewRecorder() | ||||
| @@ -108,14 +105,14 @@ func TestBinderQueryParams(t *testing.T) { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestBinderScanner(t *testing.T) { | ||||
| func TestBindUnmarshalParam(t *testing.T) { | ||||
| 	e := New() | ||||
| 	req, _ := http.NewRequest(GET, "/?ts=2016-12-06T19:09:05Z", nil) | ||||
| 	rec := httptest.NewRecorder() | ||||
| 	c := e.NewContext(req, rec) | ||||
| 	var result struct { | ||||
| 	result := struct { | ||||
| 		T Timestamp `query:"ts"` | ||||
| 	} | ||||
| 	}{} | ||||
| 	err := c.Bind(&result) | ||||
| 	if assert.NoError(t, err) { | ||||
| 		//		assert.Equal(t, Timestamp(reflect.TypeOf(&Timestamp{}), time.Date(2016, 12, 6, 19, 9, 5, 0, time.UTC)), result.T) | ||||
| @@ -123,42 +120,42 @@ func TestBinderScanner(t *testing.T) { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestBinderScannerPtr(t *testing.T) { | ||||
| func TestBindUnmarshalParamPtr(t *testing.T) { | ||||
| 	e := New() | ||||
| 	req, _ := http.NewRequest(GET, "/?ts=2016-12-06T19:09:05Z", nil) | ||||
| 	rec := httptest.NewRecorder() | ||||
| 	c := e.NewContext(req, rec) | ||||
| 	var result struct { | ||||
| 	result := struct { | ||||
| 		Tptr *Timestamp `query:"ts"` | ||||
| 	} | ||||
| 	}{} | ||||
| 	err := c.Bind(&result) | ||||
| 	if assert.NoError(t, err) { | ||||
| 		assert.Equal(t, Timestamp(time.Date(2016, 12, 6, 19, 9, 5, 0, time.UTC)), *result.Tptr) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestBinderMultipartForm(t *testing.T) { | ||||
| func TestBindMultipartForm(t *testing.T) { | ||||
| 	body := new(bytes.Buffer) | ||||
| 	mw := multipart.NewWriter(body) | ||||
| 	mw.WriteField("id", "1") | ||||
| 	mw.WriteField("name", "Jon Snow") | ||||
| 	mw.Close() | ||||
| 	testBinderOkay(t, body, mw.FormDataContentType()) | ||||
| 	testBindOkay(t, body, mw.FormDataContentType()) | ||||
| } | ||||
| 
 | ||||
| func TestBinderUnsupportedMediaType(t *testing.T) { | ||||
| 	testBinderError(t, strings.NewReader(invalidContent), MIMEApplicationJSON) | ||||
| func TestBindUnsupportedMediaType(t *testing.T) { | ||||
| 	testBindError(t, strings.NewReader(invalidContent), MIMEApplicationJSON) | ||||
| } | ||||
| 
 | ||||
| func TestBinderbindData(t *testing.T) { | ||||
| 	ts := new(binderTestStruct) | ||||
| func TestBindbindData(t *testing.T) { | ||||
| 	ts := new(bindTestStruct) | ||||
| 	b := new(DefaultBinder) | ||||
| 	b.bindData(ts, values, "form") | ||||
| 	assertBinderTestStruct(t, ts) | ||||
| 	assertBindTestStruct(t, ts) | ||||
| } | ||||
| 
 | ||||
| func TestBinderSetWithProperType(t *testing.T) { | ||||
| 	ts := new(binderTestStruct) | ||||
| func TestBindSetWithProperType(t *testing.T) { | ||||
| 	ts := new(bindTestStruct) | ||||
| 	typ := reflect.TypeOf(ts).Elem() | ||||
| 	val := reflect.ValueOf(ts).Elem() | ||||
| 	for i := 0; i < typ.NumField(); i++ { | ||||
| @@ -174,7 +171,7 @@ func TestBinderSetWithProperType(t *testing.T) { | ||||
| 		err := setWithProperType(typeField.Type.Kind(), val, structField) | ||||
| 		assert.NoError(t, err) | ||||
| 	} | ||||
| 	assertBinderTestStruct(t, ts) | ||||
| 	assertBindTestStruct(t, ts) | ||||
| 
 | ||||
| 	type foo struct { | ||||
| 		Bar bytes.Buffer | ||||
| @@ -185,8 +182,8 @@ func TestBinderSetWithProperType(t *testing.T) { | ||||
| 	assert.Error(t, setWithProperType(typ.Field(0).Type.Kind(), "5", val.Field(0))) | ||||
| } | ||||
| 
 | ||||
| func TestBinderSetFields(t *testing.T) { | ||||
| 	ts := new(binderTestStruct) | ||||
| func TestBindSetFields(t *testing.T) { | ||||
| 	ts := new(bindTestStruct) | ||||
| 	val := reflect.ValueOf(ts).Elem() | ||||
| 	// Int | ||||
| 	if assert.NoError(t, setIntField("5", 0, val.FieldByName("I"))) { | ||||
| @@ -225,7 +222,7 @@ func TestBinderSetFields(t *testing.T) { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func assertBinderTestStruct(t *testing.T, ts *binderTestStruct) { | ||||
| func assertBindTestStruct(t *testing.T, ts *bindTestStruct) { | ||||
| 	assert.Equal(t, 0, ts.I) | ||||
| 	assert.Equal(t, int8(8), ts.I8) | ||||
| 	assert.Equal(t, int16(16), ts.I16) | ||||
| @@ -243,7 +240,7 @@ func assertBinderTestStruct(t *testing.T, ts *binderTestStruct) { | ||||
| 	assert.Equal(t, "", ts.GetCantSet()) | ||||
| } | ||||
| 
 | ||||
| func testBinderOkay(t *testing.T, r io.Reader, ctype string) { | ||||
| func testBindOkay(t *testing.T, r io.Reader, ctype string) { | ||||
| 	e := New() | ||||
| 	req, _ := http.NewRequest(POST, "/", r) | ||||
| 	rec := httptest.NewRecorder() | ||||
| @@ -257,7 +254,7 @@ func testBinderOkay(t *testing.T, r io.Reader, ctype string) { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func testBinderError(t *testing.T, r io.Reader, ctype string) { | ||||
| func testBindError(t *testing.T, r io.Reader, ctype string) { | ||||
| 	e := New() | ||||
| 	req, _ := http.NewRequest(POST, "/", r) | ||||
| 	rec := httptest.NewRecorder() | ||||
| @@ -172,9 +172,9 @@ ls avatar.png | ||||
|  | ||||
| ### Handling Request | ||||
|  | ||||
| - Bind `JSON`, `XML`, `form` or `query` payload into Go struct based on `Content-Type` request header. | ||||
| - Render response as `JSON` or `XML` with status code. | ||||
| - Use the [BindUnmarshaler](https://godoc.org/github.com/labstack/echo#ParamUnmarshaler) interface to bind custom data types for `form` or `query` payloads. The standard [json.Unmarshaler](https://golang.org/pkg/encoding/json/#Unmarshaler) and [xml.Unmarshaler](https://golang.org/pkg/encoding/xml/#Unmarshaler) can of course be used for JSON and XML payloads, respectively. | ||||
| - Bind `json`, `xml`, `form` or `query` payload into Go struct based on `Content-Type` | ||||
| request header. | ||||
| - Render response as `json` or `xml` with status code. | ||||
|  | ||||
| ```go | ||||
| type User struct { | ||||
|   | ||||
| @@ -9,35 +9,27 @@ description = "Customizing Echo" | ||||
|  | ||||
| ## HTTP Error Handler | ||||
|  | ||||
| Default HTTP error handler sends an error as JSON with the following rules: | ||||
| `Echo#HTTPErrorHandler` can be used to set custom http error handler. | ||||
|  | ||||
| - If error is `Echo#HTTPError` it sends HTTP response with status code `HTTPError.Code` | ||||
| and message `HTTPError.Message`. | ||||
| - If error is `error` it sends HTTP response with status code `500 - Internal Server Error`  | ||||
| and message `error.Error()`. | ||||
| - It logs the error. | ||||
|  | ||||
| You can set a custom HTTP error handler using `Echo#HTTPErrorHandler`. | ||||
| [Learn more](/guide/error-handling) | ||||
|  | ||||
| ## Debugging | ||||
|  | ||||
| `Echo#Debug` enable/disable debug mode. | ||||
| `Echo#Debug` can be used to enable / disable debug mode. | ||||
|  | ||||
| ## Logging | ||||
|  | ||||
| ### Log Output | ||||
|  | ||||
| `Echo#Logger.SetOutput(io.Writer)` sets the output destination for the logger. | ||||
| Default value `os.Stdout` | ||||
| `Echo#Logger.SetOutput(io.Writer)` can be used to set the output destination for | ||||
| the logger. Default value is `os.Stdout` | ||||
|  | ||||
| To completely disable logs use `Echo#Logger.SetOutput(io.Discard)` or `Echo#Logger.SetLevel(log.OFF)` | ||||
|  | ||||
| ### Log Level | ||||
|  | ||||
| `Echo#Logger.SetLevel(log.Lvl)` | ||||
|  | ||||
| SetLogLevel sets the log level for the logger. Default value `OFF`. | ||||
| Possible values: | ||||
| `Echo#Logger.SetLevel(log.Lvl)` can be used to set the log level for the logger. | ||||
| Default value `OFF`. Possible values: | ||||
|  | ||||
| - `DEBUG` | ||||
| - `INFO` | ||||
| @@ -45,4 +37,6 @@ Possible values: | ||||
| - `ERROR` | ||||
| - `OFF` | ||||
|  | ||||
| You can also set a custom logger using `Echo#Logger`. | ||||
| Logging is implemented using `echo.Logger` interface which allows you to use a | ||||
| custom logger. Custom logger can be set using `Echo#Logger`. | ||||
|  | ||||
|   | ||||
| @@ -107,6 +107,20 @@ curl \ | ||||
|   -d 'name=Joe' | ||||
| ``` | ||||
|  | ||||
| To bind a custom data type, you can implement `Echo#BindUnmarshaler` interface. | ||||
|  | ||||
| *Example* | ||||
|  | ||||
| ```go | ||||
| type Timestamp time.Time | ||||
|  | ||||
| func (t *Timestamp) UnmarshalParam(src string) error { | ||||
| 	ts, err := time.Parse(time.RFC3339, src) | ||||
| 	*t = Timestamp(ts) | ||||
| 	return err | ||||
| } | ||||
| ``` | ||||
|  | ||||
| ### Query Parameters | ||||
|  | ||||
| Query parameters can be retrieved by name using `Context#QueryParam(name string)`. | ||||
| @@ -127,6 +141,8 @@ curl \ | ||||
|   http://localhost:1323\?name\=Joe | ||||
| ``` | ||||
|  | ||||
| Similar to form data, custom data type can be bind using `Context#QueryParam(name string)`. | ||||
|  | ||||
| ### Path Parameters | ||||
|  | ||||
| Registered path parameters can be retrieved by name using `Context#Param(name string) string`. | ||||
|   | ||||
		Reference in New Issue
	
	Block a user