Interceptors
Interceptors wrap handler execution, enabling logic before and after the route handler runs. Use them for logging, caching, response transformation, and error handling.
Implementing an Interceptor
type LoggingInterceptor struct {
logger gonest.Logger
}
func (i *LoggingInterceptor) Intercept(
ctx gonest.ExecutionContext,
next gonest.CallHandler,
) (any, error) {
start := time.Now()
result, err := next.Handle() // execute handler
duration := time.Since(start)
i.logger.Log("%s %s - %v", ctx.Method(), ctx.Path(), duration)
return result, err
}
Response Transformation
Wrap all responses in a standard envelope:
type TransformInterceptor struct{}
func (i *TransformInterceptor) Intercept(ctx gonest.ExecutionContext, next gonest.CallHandler) (any, error) {
result, err := next.Handle()
if err != nil {
return nil, err
}
return map[string]any{"data": result, "success": true}, nil
}
Using Interceptors
// Global
app.UseGlobalInterceptors(&LoggingInterceptor{logger: logger})
// Controller-level
r.UseInterceptors(&CacheInterceptor{})
// Route-level
r.Get("/slow", c.slow).Interceptors(&TimeoutInterceptor{})
Built-in Interceptors
SerializerInterceptor— Exclude/expose fields based on struct tagsCacheInterceptor— Cache GET responses with TTLFileInterceptor— Extract uploaded files from multipart requestsBroadcastInterceptor— Broadcast results to WebSocket clients
InterceptorFunc Shorthand
interceptor := gonest.InterceptorFunc(func(ctx gonest.ExecutionContext, next gonest.CallHandler) (any, error) {
ctx.SetHeader("X-Powered-By", "GoNest")
return next.Handle()
})