diff --git a/core/mapping/jsonunmarshaler.go b/core/mapping/jsonunmarshaler.go index 523a8ca2..7dfeb653 100644 --- a/core/mapping/jsonunmarshaler.go +++ b/core/mapping/jsonunmarshaler.go @@ -15,6 +15,11 @@ func UnmarshalJsonBytes(content []byte, v interface{}) error { return unmarshalJsonBytes(content, v, jsonUnmarshaler) } +// UnmarshalJsonMap unmarshals content from m into v. +func UnmarshalJsonMap(m map[string]interface{}, v interface{}) error { + return jsonUnmarshaler.Unmarshal(m, v) +} + // UnmarshalJsonReader unmarshals content from reader into v. func UnmarshalJsonReader(reader io.Reader, v interface{}) error { return unmarshalJsonReader(reader, v, jsonUnmarshaler) diff --git a/rest/httpx/requests.go b/rest/httpx/requests.go index 238efa24..2609030d 100644 --- a/rest/httpx/requests.go +++ b/rest/httpx/requests.go @@ -14,7 +14,6 @@ const ( formKey = "form" pathKey = "path" headerKey = "header" - emptyJson = "{}" maxMemory = 32 << 20 // 32MB maxBodyLen = 8 << 20 // 8MB separator = ";" @@ -26,6 +25,8 @@ var ( pathUnmarshaler = mapping.NewUnmarshaler(pathKey, mapping.WithStringValues()) headerUnmarshaler = mapping.NewUnmarshaler(headerKey, mapping.WithStringValues(), mapping.WithCanonicalKeyFunc(textproto.CanonicalMIMEHeaderKey)) + + emptyMap = map[string]interface{}{} ) // Parse parses the request. @@ -109,11 +110,10 @@ func ParseJsonBody(r *http.Request, v interface{}) error { var reader io.Reader if withJsonBody(r) { reader = io.LimitReader(r.Body, maxBodyLen) - } else { - reader = strings.NewReader(emptyJson) + return mapping.UnmarshalJsonReader(reader, v) } - return mapping.UnmarshalJsonReader(reader, v) + return mapping.UnmarshalJsonMap(emptyMap, v) } // ParsePath parses the symbols reside in url path. diff --git a/rest/httpx/requests_test.go b/rest/httpx/requests_test.go index 15c2cbeb..76cbe346 100644 --- a/rest/httpx/requests_test.go +++ b/rest/httpx/requests_test.go @@ -196,18 +196,38 @@ Content-Disposition: form-data; name="age" } func TestParseJsonBody(t *testing.T) { - var v struct { - Name string `json:"name"` - Age int `json:"age"` - } - body := `{"name":"kevin", "age": 18}` - r := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(body)) - r.Header.Set(ContentType, ApplicationJson) + t.Run("has body", func(t *testing.T) { + + var v struct { + Name string `json:"name"` + Age int `json:"age"` + } + + body := `{"name":"kevin", "age": 18}` + r := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(body)) + r.Header.Set(ContentType, ApplicationJson) + + assert.Nil(t, Parse(r, &v)) + assert.Equal(t, "kevin", v.Name) + assert.Equal(t, 18, v.Age) + + }) + + t.Run("hasn't body", func(t *testing.T) { + + var v struct { + Name string `json:"name,optional"` + Age int `json:"age,optional"` + } + + r := httptest.NewRequest(http.MethodGet, "/", nil) + assert.Nil(t, Parse(r, &v)) + assert.Equal(t, "", v.Name) + assert.Equal(t, 0, v.Age) + + }) - assert.Nil(t, Parse(r, &v)) - assert.Equal(t, "kevin", v.Name) - assert.Equal(t, 18, v.Age) } func TestParseRequired(t *testing.T) {