Even complicated "built-in" functionality like the interceptor framework is implemented as a filter:

Filters are the middleware of the application. They are simply funcs with a specific signature:

// github.com/robfig/revel/intercept.go var InterceptorFilter = func(c *Controller, fc []Filter) { defer invokeInterceptors(FINALLY, c) defer func() { if err := recover(); err != nil { invokeInterceptors(PANIC, c) panic(err) } }() // Invoke the BEFORE interceptors and return early, if we get a result. invokeInterceptors(BEFORE, c) if c.Result != nil { return } fc[0](c, fc[1:]) invokeInterceptors(AFTER, c) }

Revel provides a default stack of Filters which the developer can override. This makes it easy for the developer to select exactly the parts of the framework that they want to use.

// github.com/robfig/revel/filter.go // Filters is the default set of global filters. // It may be set by the application on initialization. var Filters = []Filter{ PanicFilter, // Recover from panics and display an error page instead. RouterFilter, // Use the routing table to select the right Action FilterConfiguringFilter, // A hook for adding or removing per-Action filters. ParamsFilter, // Parse parameters into Controller.Params. SessionFilter, // Restore and write the session cookie. FlashFilter, // Restore and write the flash cookie. ValidationFilter, // Restore kept validation errors and save new ones from cookie. I18nFilter, // Resolve the requested language InterceptorFilter, // Run interceptors around the action. ActionInvoker, // Invoke the action. }

Nearly all framework functionality is implemented in the filters, and the filter stack is directly exposed to the developer as part of the configuration. This makes Revel understandable and modular.

As proof of modularity, look how simple the main server handler is:

// github.com/robfig/revel/server.go func handleInternal(w http.ResponseWriter, r *http.Request, ws *websocket.Conn) { var ( req = NewRequest(r) resp = NewResponse(w) c = NewController(req, resp) ) req.Websocket = ws Filters[0](c, Filters[1:]) if c.Result != nil { c.Result.Apply(req, resp) } }