Skip to content

Commit 1dca084

Browse files
authored
Plumb JSON Decoder options (#515)
* plumb json decoder options * Unit test the WithUseNumber option * Unit test the WithDisallowUnknownFields option
1 parent 0ad0619 commit 1dca084

File tree

2 files changed

+95
-6
lines changed

2 files changed

+95
-6
lines changed

lambda/handler.go

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,14 @@ type Handler interface {
2222

2323
type handlerOptions struct {
2424
handlerFunc
25-
baseContext context.Context
26-
jsonResponseEscapeHTML bool
27-
jsonResponseIndentPrefix string
28-
jsonResponseIndentValue string
29-
enableSIGTERM bool
30-
sigtermCallbacks []func()
25+
baseContext context.Context
26+
jsonRequestUseNumber bool
27+
jsonRequestDisallowUnknownFields bool
28+
jsonResponseEscapeHTML bool
29+
jsonResponseIndentPrefix string
30+
jsonResponseIndentValue string
31+
enableSIGTERM bool
32+
sigtermCallbacks []func()
3133
}
3234

3335
type Option func(*handlerOptions)
@@ -81,6 +83,38 @@ func WithSetIndent(prefix, indent string) Option {
8183
})
8284
}
8385

86+
// WithUseNumber sets the UseNumber option on the underlying json decoder
87+
//
88+
// Usage:
89+
//
90+
// lambda.StartWithOptions(
91+
// func (event any) (any, error) {
92+
// return event, nil
93+
// },
94+
// lambda.WithUseNumber(true)
95+
// )
96+
func WithUseNumber(useNumber bool) Option {
97+
return Option(func(h *handlerOptions) {
98+
h.jsonRequestUseNumber = useNumber
99+
})
100+
}
101+
102+
// WithUseNumber sets the DisallowUnknownFields option on the underlying json decoder
103+
//
104+
// Usage:
105+
//
106+
// lambda.StartWithOptions(
107+
// func (event any) (any, error) {
108+
// return event, nil
109+
// },
110+
// lambda.WithDisallowUnknownFields(true)
111+
// )
112+
func WithDisallowUnknownFields(disallowUnknownFields bool) Option {
113+
return Option(func(h *handlerOptions) {
114+
h.jsonRequestDisallowUnknownFields = disallowUnknownFields
115+
})
116+
}
117+
84118
// WithEnableSIGTERM enables SIGTERM behavior within the Lambda platform on container spindown.
85119
// SIGKILL will occur ~500ms after SIGTERM.
86120
// Optionally, an array of callback functions to run on SIGTERM may be provided.
@@ -267,6 +301,12 @@ func reflectHandler(f interface{}, h *handlerOptions) handlerFunc {
267301
out.Reset()
268302
in := bytes.NewBuffer(payload)
269303
decoder := json.NewDecoder(in)
304+
if h.jsonRequestUseNumber {
305+
decoder.UseNumber()
306+
}
307+
if h.jsonRequestDisallowUnknownFields {
308+
decoder.DisallowUnknownFields()
309+
}
270310
encoder := json.NewEncoder(out)
271311
encoder.SetEscapeHTML(h.jsonResponseEscapeHTML)
272312
encoder.SetIndent(h.jsonResponseIndentPrefix, h.jsonResponseIndentValue)

lambda/handler_test.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"fmt"
1010
"io"
1111
"io/ioutil" //nolint: staticcheck
12+
"reflect"
1213
"strings"
1314
"testing"
1415
"time"
@@ -309,6 +310,54 @@ func TestInvokes(t *testing.T) {
309310
},
310311
options: []Option{WithSetIndent(">>", " ")},
311312
},
313+
{
314+
name: "WithUseNumber(true) results in json.Number instead of float64 when decoding to an interface{}",
315+
input: `19.99`,
316+
expected: expected{`"Number"`, nil},
317+
handler: func(event interface{}) (string, error) {
318+
return reflect.TypeOf(event).Name(), nil
319+
},
320+
options: []Option{WithUseNumber(true)},
321+
},
322+
{
323+
name: "WithUseNumber(false)",
324+
input: `19.99`,
325+
expected: expected{`"float64"`, nil},
326+
handler: func(event interface{}) (string, error) {
327+
return reflect.TypeOf(event).Name(), nil
328+
},
329+
options: []Option{WithUseNumber(false)},
330+
},
331+
{
332+
name: "No decoder options provided is the same as WithUseNumber(false)",
333+
input: `19.99`,
334+
expected: expected{`"float64"`, nil},
335+
handler: func(event interface{}) (string, error) {
336+
return reflect.TypeOf(event).Name(), nil
337+
},
338+
options: []Option{},
339+
},
340+
{
341+
name: "WithDisallowUnknownFields(true)",
342+
input: `{"Hello": "World"}`,
343+
expected: expected{"", errors.New(`json: unknown field "Hello"`)},
344+
handler: func(_ struct{}) {},
345+
options: []Option{WithDisallowUnknownFields(true)},
346+
},
347+
{
348+
name: "WithDisallowUnknownFields(false)",
349+
input: `{"Hello": "World"}`,
350+
expected: expected{`null`, nil},
351+
handler: func(_ struct{}) {},
352+
options: []Option{WithDisallowUnknownFields(false)},
353+
},
354+
{
355+
name: "No decoder options provided is the same as WithDisallowUnknownFields(false)",
356+
input: `{"Hello": "World"}`,
357+
expected: expected{`null`, nil},
358+
handler: func(_ struct{}) {},
359+
options: []Option{},
360+
},
312361
{
313362
name: "bytes are base64 encoded strings",
314363
input: `"aGVsbG8="`,

0 commit comments

Comments
 (0)