From a61556d857ccdbb277ae88d1e288bd9a9f397215 Mon Sep 17 00:00:00 2001 From: Hein Date: Tue, 2 Dec 2025 17:16:34 +0200 Subject: [PATCH] Added FallbackHandler --- pkg/resolvespec/handler.go | 31 +++++++++++++++++++++++++++---- pkg/restheadspec/handler.go | 31 +++++++++++++++++++++++++++---- 2 files changed, 54 insertions(+), 8 deletions(-) diff --git a/pkg/resolvespec/handler.go b/pkg/resolvespec/handler.go index 3beb261..21e1aa5 100644 --- a/pkg/resolvespec/handler.go +++ b/pkg/resolvespec/handler.go @@ -16,12 +16,17 @@ import ( "github.com/bitechdev/ResolveSpec/pkg/reflection" ) +// FallbackHandler is a function that handles requests when no model is found +// It receives the same parameters as the Handle method +type FallbackHandler func(w common.ResponseWriter, r common.Request, params map[string]string) + // Handler handles API requests using database and model abstractions type Handler struct { db common.Database registry common.ModelRegistry nestedProcessor *common.NestedCUDProcessor hooks *HookRegistry + fallbackHandler FallbackHandler } // NewHandler creates a new API handler with database and registry abstractions @@ -42,6 +47,12 @@ func (h *Handler) Hooks() *HookRegistry { return h.hooks } +// SetFallbackHandler sets a fallback handler to be called when no model is found +// If not set, the handler will simply return (pass through to next route) +func (h *Handler) SetFallbackHandler(fallback FallbackHandler) { + h.fallbackHandler = fallback +} + // GetDatabase returns the underlying database connection // Implements common.SpecHandler interface func (h *Handler) GetDatabase() common.Database { @@ -89,8 +100,14 @@ func (h *Handler) Handle(w common.ResponseWriter, r common.Request, params map[s // Get model and populate context with request-scoped data model, err := h.registry.GetModelByEntity(schema, entity) if err != nil { - // Model not found - pass through to next route without writing response - logger.Debug("Model not found for %s.%s, passing through to next route", schema, entity) + // Model not found - call fallback handler if set, otherwise pass through + logger.Debug("Model not found for %s.%s", schema, entity) + if h.fallbackHandler != nil { + logger.Debug("Calling fallback handler for %s.%s", schema, entity) + h.fallbackHandler(w, r, params) + } else { + logger.Debug("No fallback handler set, passing through to next route") + } return } @@ -156,8 +173,14 @@ func (h *Handler) HandleGet(w common.ResponseWriter, r common.Request, params ma model, err := h.registry.GetModelByEntity(schema, entity) if err != nil { - // Model not found - pass through to next route without writing response - logger.Debug("Model not found for %s.%s, passing through to next route", schema, entity) + // Model not found - call fallback handler if set, otherwise pass through + logger.Debug("Model not found for %s.%s", schema, entity) + if h.fallbackHandler != nil { + logger.Debug("Calling fallback handler for %s.%s", schema, entity) + h.fallbackHandler(w, r, params) + } else { + logger.Debug("No fallback handler set, passing through to next route") + } return } diff --git a/pkg/restheadspec/handler.go b/pkg/restheadspec/handler.go index 3b5080a..0c58ea6 100644 --- a/pkg/restheadspec/handler.go +++ b/pkg/restheadspec/handler.go @@ -17,6 +17,10 @@ import ( "github.com/bitechdev/ResolveSpec/pkg/reflection" ) +// FallbackHandler is a function that handles requests when no model is found +// It receives the same parameters as the Handle method +type FallbackHandler func(w common.ResponseWriter, r common.Request, params map[string]string) + // Handler handles API requests using database and model abstractions // This handler reads filters, columns, and options from HTTP headers type Handler struct { @@ -24,6 +28,7 @@ type Handler struct { registry common.ModelRegistry hooks *HookRegistry nestedProcessor *common.NestedCUDProcessor + fallbackHandler FallbackHandler } // NewHandler creates a new API handler with database and registry abstractions @@ -50,6 +55,12 @@ func (h *Handler) Hooks() *HookRegistry { return h.hooks } +// SetFallbackHandler sets a fallback handler to be called when no model is found +// If not set, the handler will simply return (pass through to next route) +func (h *Handler) SetFallbackHandler(fallback FallbackHandler) { + h.fallbackHandler = fallback +} + // handlePanic is a helper function to handle panics with stack traces func (h *Handler) handlePanic(w common.ResponseWriter, method string, err interface{}) { stack := debug.Stack() @@ -81,8 +92,14 @@ func (h *Handler) Handle(w common.ResponseWriter, r common.Request, params map[s // Get model and populate context with request-scoped data model, err := h.registry.GetModelByEntity(schema, entity) if err != nil { - // Model not found - pass through to next route without writing response - logger.Debug("Model not found for %s.%s, passing through to next route", schema, entity) + // Model not found - call fallback handler if set, otherwise pass through + logger.Debug("Model not found for %s.%s", schema, entity) + if h.fallbackHandler != nil { + logger.Debug("Calling fallback handler for %s.%s", schema, entity) + h.fallbackHandler(w, r, params) + } else { + logger.Debug("No fallback handler set, passing through to next route") + } return } @@ -197,8 +214,14 @@ func (h *Handler) HandleGet(w common.ResponseWriter, r common.Request, params ma model, err := h.registry.GetModelByEntity(schema, entity) if err != nil { - // Model not found - pass through to next route without writing response - logger.Debug("Model not found for %s.%s, passing through to next route", schema, entity) + // Model not found - call fallback handler if set, otherwise pass through + logger.Debug("Model not found for %s.%s", schema, entity) + if h.fallbackHandler != nil { + logger.Debug("Calling fallback handler for %s.%s", schema, entity) + h.fallbackHandler(w, r, params) + } else { + logger.Debug("No fallback handler set, passing through to next route") + } return }