add Context.SetJSONOptions

This commit is contained in:
Gerasimos (Makis) Maropoulos 2022-03-31 20:47:01 +03:00
parent cf36063adf
commit 84d1a60334
No known key found for this signature in database
GPG Key ID: 66FCC29BD385FCA6
3 changed files with 55 additions and 9 deletions

View File

@ -28,6 +28,9 @@ The codebase for Dependency Injection, Internationalization and localization and
## Fixes and Improvements
- Add `Context.SetJSONOptions` to customize on a higher level the JSON options on `Context.JSON` calls.
- Add new `sso` sub-package which helps on any user type auth using JWT (access & refresh tokens) and a cookie (optional).
- Add `Party.EnsureStaticBindings` which, if called, the MVC binder panics if a struct's input binding depends on the HTTP request data instead of a static dependency. This is useful to make sure your API crafted through `Party.PartyConfigure` depends only on struct values you already defined at `Party.RegisterDependency` == will never use reflection at serve-time (maximum performance).
- Add a new [x/sqlx](/x/sqlx/) sub-package ([example](_examples/database/sqlx/main.go)).

View File

@ -3761,6 +3761,16 @@ type JSON struct {
// Optional context cancelation of encoder when Iris optimizations field is enabled.
// On JSON method this is automatically binded to the request context.
Context stdContext.Context
// ErrorHandler can be optionally registered to fire a customized
// error to the client on JSON write failures.
ErrorHandler ErrorHandler
}
// ErrorHandler describes a context error handler. As for today this is only used
// to globally or per-party or per-route handle JSON writes error.
type ErrorHandler interface {
HandleContextError(ctx *Context, err error)
}
// IsDefault reports whether this JSON options structure holds the default values.
@ -3771,7 +3781,8 @@ func (j *JSON) IsDefault() bool {
j.Prefix == DefaultJSONOptions.Prefix &&
j.ASCII == DefaultJSONOptions.ASCII &&
j.Secure == DefaultJSONOptions.Secure &&
j.Proto == DefaultJSONOptions.Proto
j.Proto == DefaultJSONOptions.Proto &&
j.ErrorHandler == nil
}
// GetContext returns the option's Context or the HTTP request's one.
@ -3942,18 +3953,55 @@ func stringToBytes(s string) []byte {
// inside `ctx.JSON`.
var DefaultJSONOptions = JSON{}
const jsonOptionsContextKey = "iris.context.json_options"
// SetJSONOptions stores the given JSON options to the handler
// for any next Context.JSON calls. Note that the Context.JSON's
// variadic options have priority over these given options.
func (ctx *Context) SetJSONOptions(opts JSON) {
ctx.values.Set(jsonOptionsContextKey, opts)
}
func (ctx *Context) getJSONOptions() (JSON, bool) {
if v := ctx.values.Get(jsonOptionsContextKey); v != nil {
opts, ok := v.(JSON)
return opts, ok
}
return DefaultJSONOptions, false
}
// JSON marshals the given interface object and writes the JSON response to the client.
// If the value is a compatible `proto.Message` one
// then it only uses the options.Proto settings to marshal.
func (ctx *Context) JSON(v interface{}, opts ...JSON) (n int, err error) {
if n, err = ctx.writeJSON(v, opts...); err != nil {
if opts, ok := ctx.getJSONOptions(); ok {
opts.ErrorHandler.HandleContextError(ctx, err)
} // keep the error so the caller has control over further actions.
}
return
}
func (ctx *Context) writeJSON(v interface{}, opts ...JSON) (n int, err error) {
ctx.ContentType(ContentJSONHeaderValue)
shouldOptimize := ctx.shouldOptimize()
options := DefaultJSONOptions
optsLength := len(opts)
if optsLength > 0 {
options = opts[0]
} else {
if opt, ok := ctx.getJSONOptions(); ok {
opts = []JSON{opt}
optsLength = 1
}
}
if shouldOptimize && optsLength == 0 { // if no options given and optimizations are enabled.
// try handle proto or easyjson.
if handled, n, err := handleJSONResponseValue(ctx, v, DefaultJSONOptions); handled {
if handled, n, err := handleJSONResponseValue(ctx, v, options); handled {
return n, err
}
@ -3966,11 +4014,6 @@ func (ctx *Context) JSON(v interface{}, opts ...JSON) (n int, err error) {
return ctx.Write(result)
}
options := DefaultJSONOptions
if optsLength > 0 {
options = opts[0]
}
if options.StreamingJSON {
if shouldOptimize {
// jsoniterConfig := jsoniter.Config{

View File

@ -248,7 +248,7 @@ type Error struct {
}
// Error method completes the error interface. It just returns the canonical name, status code, message and details.
func (err Error) Error() string {
func (err *Error) Error() string {
if err.Message == "" {
err.Message = "<empty>"
}
@ -312,6 +312,6 @@ func fail(ctx *context.Context, codeName ErrorCodeName, msg, details string, val
Validation: validationErrors,
}
// ctx.SetErr(err)
// ctx.SetErr(&err)
ctx.StopWithJSON(errorCode.Status, err)
}