From 6d3884b0ceba66173ae068e4d44c593e9e34856e Mon Sep 17 00:00:00 2001 From: "Gerasimos (Makis) Maropoulos" Date: Wed, 16 Jun 2021 13:52:39 +0300 Subject: [PATCH] add iris.IsErrEmptyJSON helper. See HISTORY.md --- HISTORY.md | 19 +++++++++++++++++ .../basic/middleware/main.go | 6 ++++++ aliases.go | 4 ++++ context/context.go | 21 +++++++++++++++++-- 4 files changed, 48 insertions(+), 2 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index 6b9230e0..077d2058 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -28,6 +28,25 @@ The codebase for Dependency Injection, Internationalization and localization and ## Fixes and Improvements +- New `iris.IsErrEmptyJSON(err) bool` which reports whether the given "err" is caused by a +`Context.ReadJSON` call when the request body didn't start with { (or it was totally empty). + +Example Code: + +```go +func handler(ctx iris.Context) { + var opts SearchOptions + if err := ctx.ReadJSON(&opts); err != nil && !iris.IsErrEmptyJSON(err) { + ctx.StopWithJSON(iris.StatusBadRequest, iris.Map{"message": "unable to parse body"}) + return + } + + // [...continue with default values of "opts" struct if the client didn't provide some] +} +``` + +That means that the client can optionally set a JSON body. + - New `APIContainer.EnableStrictMode(bool)` to disable automatic payload binding and panic on missing dependencies for exported struct'sfields or function's input parameters on MVC controller or hero function or PartyConfigurator. - New `Party.PartyConfigure(relativePath string, partyReg ...PartyConfigurator) Party` helper, registers a children Party like `Party` and `PartyFunc` but instead it accepts a structure value which may contain one or more of the dependencies registered by `RegisterDependency` or `ConfigureContainer().RegisterDependency` methods and fills the unset/zero exported struct's fields respectfully (useful when the api's dependencies amount are too much to pass on a function). diff --git a/_examples/dependency-injection/basic/middleware/main.go b/_examples/dependency-injection/basic/middleware/main.go index 6faf607d..137b3d61 100644 --- a/_examples/dependency-injection/basic/middleware/main.go +++ b/_examples/dependency-injection/basic/middleware/main.go @@ -47,6 +47,12 @@ func newApp() *iris.Application { // or 202 status code and empty body // or a 409 status code and "my_error" body. app.ConfigureContainer(func(api *iris.APIContainer) { + // TODO: fix that test as well. + // api.Self.SetExecutionRules(iris.ExecutionRules{ + // Begin: iris.ExecutionOptions{ + // Force: true, + // }, + // }) api.Use(middleware) api.Post("/{id:int}", handler) }) diff --git a/aliases.go b/aliases.go index a70c7ef8..cc037359 100644 --- a/aliases.go +++ b/aliases.go @@ -496,6 +496,10 @@ var ( // A shortcut for the `context#CookieEncoding`. CookieEncoding = context.CookieEncoding + // IsErrEmptyJSON reports whether the given "err" is caused by a + // Context.ReadJSON call when the request body + // didn't start with { or it was totally empty. + IsErrEmptyJSON = context.IsErrEmptyJSON // IsErrPath can be used at `context#ReadForm` and `context#ReadQuery`. // It reports whether the incoming error is type of `schema.ErrPath`, // which can be ignored when server allows unknown post values to be sent by the client. diff --git a/context/context.go b/context/context.go index 600c3227..96414fb9 100644 --- a/context/context.go +++ b/context/context.go @@ -2311,13 +2311,13 @@ func (ctx *Context) decodeBody(outPtr interface{}, decoder internalBodyDecoder) // but this is up to the user's custom Decode implementation* // // See 'BodyDecoder' for more. - if decoder, isDecoder := outPtr.(BodyDecoder); isDecoder { + if structDecoder, isDecoder := outPtr.(BodyDecoder); isDecoder { rawData, err := ctx.GetBody() if err != nil { return err } - return decoder.Decode(rawData) + return structDecoder.Decode(rawData) } err := decoder.Decode(outPtr) @@ -2465,6 +2465,23 @@ func (ctx *Context) ReadYAML(outPtr interface{}) error { } var ( + // IsErrEmptyJSON reports whether the given "err" is caused by a + // Context.ReadJSON call when the request body + // didn't start with { or it was totally empty. + IsErrEmptyJSON = func(err error) bool { + if err == nil { + return false + } + + if v, ok := err.(*json.SyntaxError); ok { + // standard go json encoder error. + return v.Offset == 0 && v.Error() == "unexpected end of JSON input" + } + + // when optimization is enabled, the jsoniter will report the following error: + return strings.Contains(err.Error(), "readObjectStart: expect {") + } + // IsErrPath can be used at `context#ReadForm` and `context#ReadQuery`. // It reports whether the incoming error // can be ignored when server allows unknown post values to be sent by the client.