diff --git a/ginext/engine.go b/ginext/engine.go index dcc747d..1d0bf5c 100644 --- a/ginext/engine.go +++ b/ginext/engine.go @@ -27,6 +27,8 @@ type GinWrapper struct { listenerBeforeRequest []func(g *gin.Context) listenerAfterRequest []func(g *gin.Context, resp HTTPResponse) + buildRequestBindError func(g *gin.Context, fieldtype string, err error) HTTPResponse + routeSpecs []ginRouteSpec } @@ -38,15 +40,16 @@ type ginRouteSpec struct { } type Options struct { - AllowCors *bool // Add cors handler to allow all CORS requests on the default http methods - GinDebug *bool // Set gin.debug to true (adds more logs) - SuppressGinLogs *bool // Suppress our custom gin logs (even if GinDebug == true) - BufferBody *bool // Buffers the input body stream, this way the ginext error handler can later include the whole request body - Timeout *time.Duration // The default handler timeout - ListenerBeforeRequest []func(g *gin.Context) // Register listener that are called before the handler method - ListenerAfterRequest []func(g *gin.Context, resp HTTPResponse) // Register listener that are called after the handler method - DebugTrimHandlerPrefixes []string // Trim these prefixes from the handler names in the debug print - DebugReplaceHandlerNames map[string]string // Replace handler names in debug output + AllowCors *bool // Add cors handler to allow all CORS requests on the default http methods + GinDebug *bool // Set gin.debug to true (adds more logs) + SuppressGinLogs *bool // Suppress our custom gin logs (even if GinDebug == true) + BufferBody *bool // Buffers the input body stream, this way the ginext error handler can later include the whole request body + Timeout *time.Duration // The default handler timeout + ListenerBeforeRequest []func(g *gin.Context) // Register listener that are called before the handler method + ListenerAfterRequest []func(g *gin.Context, resp HTTPResponse) // Register listener that are called after the handler method + DebugTrimHandlerPrefixes []string // Trim these prefixes from the handler names in the debug print + DebugReplaceHandlerNames map[string]string // Replace handler names in debug output + BuildRequestBindError func(g *gin.Context, fieldtype string, err error) HTTPResponse // Override function which generates the HTTPResponse errors that are returned by the preContext..Start() methids } // NewEngine creates a new (wrapped) ginEngine @@ -77,6 +80,7 @@ func NewEngine(opt Options) *GinWrapper { requestTimeout: langext.Coalesce(opt.Timeout, 24*time.Hour), listenerBeforeRequest: opt.ListenerBeforeRequest, listenerAfterRequest: opt.ListenerAfterRequest, + buildRequestBindError: langext.Conditional(opt.BuildRequestBindError == nil, defaultBuildRequestBindError, opt.BuildRequestBindError), } engine.RedirectFixedPath = false @@ -222,3 +226,7 @@ func (w *GinWrapper) ForwardRequest(writer http.ResponseWriter, req *http.Reques func (w *GinWrapper) ListRoutes() []gin.RouteInfo { return w.engine.Routes() } + +func defaultBuildRequestBindError(g *gin.Context, fieldtype string, err error) HTTPResponse { + return Error(err) +} diff --git a/ginext/preContext.go b/ginext/preContext.go index 6ab4497..537b91b 100644 --- a/ginext/preContext.go +++ b/ginext/preContext.go @@ -77,14 +77,14 @@ func (pctx *PreContext) IgnoreWrongContentType() *PreContext { return pctx } -func (pctx PreContext) Start() (*AppContext, *gin.Context, *InspectableHTTPErrorResponse) { +func (pctx PreContext) Start() (*AppContext, *gin.Context, *HTTPResponse) { if pctx.uri != nil { if err := pctx.ginCtx.ShouldBindUri(pctx.uri); err != nil { err = exerr.Wrap(err, "Failed to read uri"). WithType(exerr.TypeBindFailURI). Str("struct_type", fmt.Sprintf("%T", pctx.uri)). Build() - return nil, nil, langext.Ptr(Error(err)) + return nil, nil, langext.Ptr(pctx.wrapper.buildRequestBindError(pctx.ginCtx, "URI", err)) } } @@ -94,7 +94,7 @@ func (pctx PreContext) Start() (*AppContext, *gin.Context, *InspectableHTTPError WithType(exerr.TypeBindFailQuery). Str("struct_type", fmt.Sprintf("%T", pctx.query)). Build() - return nil, nil, langext.Ptr(Error(err)) + return nil, nil, langext.Ptr(pctx.wrapper.buildRequestBindError(pctx.ginCtx, "QUERY", err)) } } @@ -105,14 +105,14 @@ func (pctx PreContext) Start() (*AppContext, *gin.Context, *InspectableHTTPError WithType(exerr.TypeBindFailJSON). Str("struct_type", fmt.Sprintf("%T", pctx.body)). Build() - return nil, nil, langext.Ptr(Error(err)) + return nil, nil, langext.Ptr(pctx.wrapper.buildRequestBindError(pctx.ginCtx, "BODY", err)) } } else { if !pctx.ignoreWrongContentType { err := exerr.New(exerr.TypeBindFailJSON, "missing JSON body"). Str("struct_type", fmt.Sprintf("%T", pctx.body)). Build() - return nil, nil, langext.Ptr(Error(err)) + return nil, nil, langext.Ptr(pctx.wrapper.buildRequestBindError(pctx.ginCtx, "BODY", err)) } } } @@ -121,14 +121,14 @@ func (pctx PreContext) Start() (*AppContext, *gin.Context, *InspectableHTTPError if brc, ok := pctx.ginCtx.Request.Body.(dataext.BufferedReadCloser); ok { v, err := brc.BufferedAll() if err != nil { - return nil, nil, langext.Ptr(Error(err)) + return nil, nil, langext.Ptr(pctx.wrapper.buildRequestBindError(pctx.ginCtx, "URI", err)) } *pctx.rawbody = v } else { buf := &bytes.Buffer{} _, err := io.Copy(buf, pctx.ginCtx.Request.Body) if err != nil { - return nil, nil, langext.Ptr(Error(err)) + return nil, nil, langext.Ptr(pctx.wrapper.buildRequestBindError(pctx.ginCtx, "URI", err)) } *pctx.rawbody = buf.Bytes() } @@ -141,7 +141,7 @@ func (pctx PreContext) Start() (*AppContext, *gin.Context, *InspectableHTTPError WithType(exerr.TypeBindFailFormData). Str("struct_type", fmt.Sprintf("%T", pctx.form)). Build() - return nil, nil, langext.Ptr(Error(err)) + return nil, nil, langext.Ptr(pctx.wrapper.buildRequestBindError(pctx.ginCtx, "FORM", err)) } } else if pctx.ginCtx.ContentType() == "application/x-www-form-urlencoded" { if err := pctx.ginCtx.ShouldBindWith(pctx.form, binding.Form); err != nil { @@ -149,14 +149,14 @@ func (pctx PreContext) Start() (*AppContext, *gin.Context, *InspectableHTTPError WithType(exerr.TypeBindFailFormData). Str("struct_type", fmt.Sprintf("%T", pctx.form)). Build() - return nil, nil, langext.Ptr(Error(err)) + return nil, nil, langext.Ptr(pctx.wrapper.buildRequestBindError(pctx.ginCtx, "FORM", err)) } } else { if !pctx.ignoreWrongContentType { err := exerr.New(exerr.TypeBindFailFormData, "missing form body"). Str("struct_type", fmt.Sprintf("%T", pctx.form)). Build() - return nil, nil, langext.Ptr(Error(err)) + return nil, nil, langext.Ptr(pctx.wrapper.buildRequestBindError(pctx.ginCtx, "FORM", err)) } } } @@ -167,7 +167,7 @@ func (pctx PreContext) Start() (*AppContext, *gin.Context, *InspectableHTTPError WithType(exerr.TypeBindFailHeader). Str("struct_type", fmt.Sprintf("%T", pctx.query)). Build() - return nil, nil, langext.Ptr(Error(err)) + return nil, nil, langext.Ptr(pctx.wrapper.buildRequestBindError(pctx.ginCtx, "HEADER", err)) } } @@ -179,7 +179,7 @@ func (pctx PreContext) Start() (*AppContext, *gin.Context, *InspectableHTTPError err := pctx.persistantData.sessionObj.Init(pctx.ginCtx, actx) if err != nil { actx.Cancel() - return nil, nil, langext.Ptr(Error(exerr.Wrap(err, "Failed to init session").Build())) + return nil, nil, langext.Ptr(pctx.wrapper.buildRequestBindError(pctx.ginCtx, "INIT", err)) } } diff --git a/ginext/response.go b/ginext/response.go index 242b24b..27b1fb4 100644 --- a/ginext/response.go +++ b/ginext/response.go @@ -36,9 +36,8 @@ type InspectableHTTPResponse interface { Headers() []string } -type InspectableHTTPErrorResponse interface { +type HTTPErrorResponse interface { HTTPResponse - InspectableHTTPResponse Error() error } diff --git a/goextVersion.go b/goextVersion.go index 76d62b1..eadb4b1 100644 --- a/goextVersion.go +++ b/goextVersion.go @@ -1,5 +1,5 @@ package goext -const GoextVersion = "0.0.483" +const GoextVersion = "0.0.484" -const GoextVersionTimestamp = "2024-07-16T15:08:37+0200" +const GoextVersionTimestamp = "2024-07-16T15:16:56+0200"