diff --git a/pkg/ffapi/handler.go b/pkg/ffapi/handler.go index 40e5487..504ce8a 100644 --- a/pkg/ffapi/handler.go +++ b/pkg/ffapi/handler.go @@ -181,7 +181,9 @@ func (hs *HandlerFactory) RouteHandler(route *Route) http.HandlerFunc { fallthrough case strings.HasPrefix(strings.ToLower(contentType), "application/json"): if jsonInput != nil { - err = json.NewDecoder(req.Body).Decode(&jsonInput) + d := json.NewDecoder(req.Body) + d.UseNumber() + err = d.Decode(&jsonInput) } case strings.HasPrefix(strings.ToLower(contentType), "text/plain"): default: diff --git a/pkg/ffapi/handler_test.go b/pkg/ffapi/handler_test.go index b8ffd21..bc024ec 100644 --- a/pkg/ffapi/handler_test.go +++ b/pkg/ffapi/handler_test.go @@ -21,8 +21,6 @@ import ( "context" "encoding/json" "fmt" - "github.com/getkin/kin-openapi/openapi3" - "github.com/stretchr/testify/require" "io" "mime/multipart" "net/http" @@ -31,6 +29,9 @@ import ( "testing" "time" + "github.com/getkin/kin-openapi/openapi3" + "github.com/stretchr/testify/require" + "github.com/gorilla/mux" "github.com/hyperledger/firefly-common/pkg/config" "github.com/hyperledger/firefly-common/pkg/httpserver" @@ -38,6 +39,14 @@ import ( "github.com/stretchr/testify/assert" ) +const largeParamLiteral = `{ + "largeNumberParam": 10000000000000000000000000001 +}` + +const scientificParamLiteral = `{ + "scientificNumberParam": 1e+24 +}` + const configDir = "../../test/data/config" func newTestHandlerFactory(basePath string, basePathParams []*PathParam) *HandlerFactory { @@ -112,6 +121,62 @@ func TestRouteServePOST201WithParams(t *testing.T) { assert.Equal(t, "value2", resJSON["output1"]) } +func TestRouteServePOST201WithParamsLargeNumber(t *testing.T) { + s, _, done := newTestServer(t, []*Route{{ + Name: "testRoute", + Path: "/test/{something}", + Method: "POST", + PathParams: []*PathParam{}, + QueryParams: []*QueryParam{}, + JSONInputValue: func() interface{} { return make(map[string]interface{}) }, + JSONOutputValue: func() interface{} { return make(map[string]interface{}) }, + JSONOutputCodes: []int{201}, + JSONHandler: func(r *APIRequest) (output interface{}, err error) { + assert.Equal(t, r.Input, map[string]interface{}{"largeNumberParam": json.Number("10000000000000000000000000001")}) + // Echo the input back as the response + return r.Input, nil + }, + }}, "", nil) + defer done() + + res, err := http.Post(fmt.Sprintf("http://%s/test/stuff", s.Addr()), "application/json", bytes.NewReader([]byte(largeParamLiteral))) + assert.NoError(t, err) + assert.Equal(t, 201, res.StatusCode) + var resJSON map[string]interface{} + d := json.NewDecoder(res.Body) + d.UseNumber() + d.Decode(&resJSON) + assert.Equal(t, json.Number("10000000000000000000000000001"), resJSON["largeNumberParam"]) +} + +func TestRouteServePOST201WithParamsScientificNumber(t *testing.T) { + s, _, done := newTestServer(t, []*Route{{ + Name: "testRoute", + Path: "/test/{something}", + Method: "POST", + PathParams: []*PathParam{}, + QueryParams: []*QueryParam{}, + JSONInputValue: func() interface{} { return make(map[string]interface{}) }, + JSONOutputValue: func() interface{} { return make(map[string]interface{}) }, + JSONOutputCodes: []int{201}, + JSONHandler: func(r *APIRequest) (output interface{}, err error) { + assert.Equal(t, r.Input, map[string]interface{}{"scientificNumberParam": json.Number("1e+24")}) + // Echo the input back as the response + return r.Input, nil + }, + }}, "", nil) + defer done() + + res, err := http.Post(fmt.Sprintf("http://%s/test/stuff", s.Addr()), "application/json", bytes.NewReader([]byte(scientificParamLiteral))) + assert.NoError(t, err) + assert.Equal(t, 201, res.StatusCode) + var resJSON map[string]interface{} + d := json.NewDecoder(res.Body) + d.UseNumber() + d.Decode(&resJSON) + assert.Equal(t, json.Number("1e+24"), resJSON["scientificNumberParam"]) +} + func TestJSONHTTPResponseEncodeFail(t *testing.T) { s, _, done := newTestServer(t, []*Route{{ Name: "testRoute",