Goku

Golang Web Mvc Framework

View the Project on GitHub qleelulu/goku

Filter

Controllers define action methods that usually have a one-to-one relationship with possible user interactions, such as clicking a link or submitting a form. For example, when the user clicks a link, a request is routed to the designated controller, and the corresponding action method is called.

Sometimes you want to perform logic either before an action method is called or after an action method runs. To support this, Goku provides filters. Filters are custom stuct that provide both a declarative and programmatic means to add pre-action and post-action behavior to controller action methods.

How To Create Filter

To create a filter, just implement the Filter interface.

type Filter interface {
    OnActionExecuting(ctx *HttpContext) (ActionResulter, error)
    OnActionExecuted(ctx *HttpContext) (ActionResulter, error)
    OnResultExecuting(ctx *HttpContext) (ActionResulter, error)
    OnResultExecuted(ctx *HttpContext) (ActionResulter, error)
}

Order of the filters execution is:

1. OnActionExecuting
2. -> Execute Action -> return ActionResulter
3. OnActionExecuted
4. OnResultExecuting
5. -> ActionResulter.ExecuteResult
6. OnResultExecuted

If you want cancel the request(end the request) in the filter, you can return an ActionResulter or return error.

Here is a example show how to create a Auth filter.

type RequireLoginFilter struct {
}

func (f *RequireLoginFilter) OnActionExecuting(ctx *goku.HttpContext) (ar goku.ActionResulter, err error) {
    c, err := ctx.Request.Cookie("user")
    if err == nil {
        user, _ := users.GetByTicket(c.Value)
        if user != nil {
            // we can set data to ctx.Data,
            // then we can get it any where.
            ctx.Data["user"] = user
            return
        }
    }
    if ctx.IsAjax() {
        ar = ctx.Json(map[string]interface{}{
            "success":   false,
            "needLogin": true,
            "errors":    "Please Login",
        })
    } else {
        ar = ctx.Redirect("/user/login?returnurl=" + url.QueryEscape(ctx.Request.RequestURI))
    }
    return
}

func (f *RequireLoginFilter) OnActionExecuted(ctx *goku.HttpContext) (goku.ActionResulter, error) {
    return nil, nil
}

func (f *RequireLoginFilter) OnResultExecuting(ctx *goku.HttpContext) (goku.ActionResulter, error) {
    return nil, nil
}

func (f *RequireLoginFilter) OnResultExecuted(ctx *goku.HttpContext) (goku.ActionResulter, error) {
    return nil, nil
}

And then we can apply this filter to controller:

var _ = goku.Controller("home").
    // apply filter to controller,
    // all this controller's actions.
    Filters(&RequireLoginFilter{}).
    // index action
    Get("index", , func(ctx *goku.HttpContext) goku.ActionResulter {
        return ctx.View(nil)
    })

Or we can only apply the filter to the specified action.

var _ = goku.Controller("home").
    // index action
    Get("index", , func(ctx *goku.HttpContext) goku.ActionResulter {
        return ctx.View(nil)
    }).
    // only apply filter to index action
    Filters(&RequireLoginFilter{})