An Interceptor is a function that is invoked by the framework BEFORE or AFTER an action invocation. It allows a form of Aspect Oriented Programming, which is useful for some common concerns such as:

  • Request logging
  • Error handling
  • Statistics logging
  • Authentication handling

In Revel, an interceptor can take one of three forms:

An Interceptor has an intercept point in the request (When) and returns a Result or nil.

NOTE: Interceptors are called in the order that they are added.

Function Interceptor

  • A function meeting the InterceptorFunc interface.
  • Does not have access to the specific Controller invoked.
  • May be applied to any / all Controllers in an application (by adding lines of code).
// simple example or user auth
func checkUser(c *revel.Controller) revel.Result {
    if user := MyCheckAuth(c); user == nil {
        c.Flash.Error("Please log in first")
        return c.Redirect(App.Index)
    }
    return nil
}
func doNothing(c *revel.Controller) revel.Result { return nil }

func init() {
    revel.InterceptFunc(checkUser, revel.BEFORE, &App{})
    revel.InterceptFunc(doNothing, revel.AFTER, &App{})
    revel.InterceptFunc(checkUser, revel.BEFORE, &AnotherController{})
}

Method Interceptor

  • A InterceptorMethod method accepting no arguments and returning a revel.Result.
  • May only intercept calls to the bound Controller.
  • May modify the invoked controller as desired.
  • A method interceptor signature may have one of these two forms, or both:
    • func (c AppController) example() revel.Result
    • func (c *AppController) example() revel.Result // pointer
// simple method example

func (c Hotels) checkUser() revel.Result {
    if user := connected(c); user == nil {
        c.Flash.Error("Please log in first")
        return c.Redirect(App.Index)
    }
    return nil
}
    
func init() {
    revel.InterceptMethod(Hotels.checkUser, revel.BEFORE)
    revel.InterceptMethod(Room.checkVacant, revel.BEFORE)
}

Controller Auto Interceptor

Controllers that have methods named Before,After,Finally,Panic, will be called in the same manner as the interceptor does. The method signature is a little different then normal to allow for method Overriding and cascades. ie if Application has GorpController controller embedded inside it and both define the Before method then what happens is the GorpController.Before is invoked before the Application.Before. The method signature must match the following syntax

func (c Application) Before() (r revel.Result, a Application) {
...
func (c *GorpController) Before() (result revel.Result, controller *GorpController) {

Notice along with the revel.Result we return the Controller type. This is so when the application starts up it can determine which method belongs to what field in the controller (currently Go does not tell you this information). These work identical to the revel.Interceptors without any configuration.

On the Before method the deepest embedded struct with the Before method is run first, then the next deepest and so on until the top level. After, Finally, Panic are run from the top down

Controller Auto Interceptor Implementation

Add the filter revel.BeforeAfterFilter to revel.Filters on app/init.go. Ensure your function names match func (c Application) Before() (r revel.Result, a Application)

Intercept Times

An interceptor can be registered to run at four points in the request lifecycle; defined in When:

  1. BEFORE
  2. AFTER
    • After the request has returned a Result, but before that Result has been applied. These interceptors are not invoked if the action panicked.
  3. PANIC
    • After a panic exits an action or is raised from applying the returned Result.
  4. FINALLY
    • After an action has completed and the Result has been applied.

Results

Interceptors typically return nil, in which case the request continues to be processed without interruption.

The effect of returning a non-nil revel.Result depends on When() the interceptor was invoked.

  1. BEFORE
    • No further interceptors are invoked, and neither is the action.
  2. AFTER
    • All interceptors are still run.
  3. PANIC
    • All interceptors are still run.
  4. FINALLY
    • All interceptors are still run.

In all cases, any returned Result will take the place of any existing Result.

  • However, in the BEFORE case, the returned Result is guaranteed to be final,
  • While in the AFTER case it is possible that a further interceptor could emit its own Result.
GoDoc Reference
GitHub Labels