Skip to content

Latest commit

 

History

History
164 lines (109 loc) · 5.2 KB

README_FILTERS.md

File metadata and controls

164 lines (109 loc) · 5.2 KB

Filters

The functionality of Chicago Boss can be extended with filter modules. Filters are ideal for implementing site-wide or controller-specific features, such as authentication. Filters can be chained together and reused, which makes them ideal for implementing and distributing plug-in features. Chicago Boss uses filters internally to implement caching.

CB supports three kinds of filters: before filters, middle filters, and after filters. A filter module can implement multiple kinds of filters as described below.

Before filters

Before filters can either transform an incoming request before it is handled by a controller action, or it can short-circuit the request processing and return an action return value itself. Before filters are ideal for implementing authentication and authorization; the filter can attach the identity of the logged-in user to the incoming request, and immediately redirect unidentified or unauthorized users.

A before filter should export a function `before_filter/2':

before_filter(FilterConfig, RequestContext) -> {ok, RequestContext} | <controller return value>

The first argument is the filter's configuration value (see "Filter configuration" below). This value can be defined in the configuration file and overridden by controllers on a per-request basis.

The second argument is the request context. The request context is a proplist with the following keys:

  • `request'
  • `session_id'
  • `action'
  • `controller_module'
  • `tokens'

If the before_filter' function returns {ok, NewContext}', the NewContext' will be used for the rest of the request. You are free to modify values in the context or insert new values (e.g. logged_in_user').

Example:

-module(my_before_filter).
-export([before_filter/2]).

before_filter(_Config, RequestContext) ->
    IsAdmin = is_admin(RequestContext),
    {ok, [{is_admin, IsAdmin}|RequestContext]}.

Middle filters

A middle filter transforms a controller return value to another controller return value. Because controllers can return `{StatusCode, Payload, Headers}', you can also use it to implement custom return values.

A middle filter should export a function `middle_filter/3':

middle_filter(ReturnValue, FilterConfig, RequestContext) -> NewReturnValue

For example, if you wanted to implement a file handler `{file, PathToFile}':

-module(my_middle_filter).
-export([middle_filter/3]).

middle_filter({file, PathToFile}, _Config, _RequestContext) ->
    FileContents = read_file_somehow(PathToFile),
    FileMIMEType = figure_out_mime_type(PathToFile),
    {200, FileContents, [{"Content-Type", FileMIMEType}]};

middle_filter(Other, _, _) -> Other.

You might also use middle filters to insert commonly used values into the variable list before template rendering.

After filters

An after filter transforms a `{StatusCode, Payload, Headers}' tuple just before a response is returned to the client:

after_filter({StatusCode, Payload, Headers}, RequestContext) -> {NewStatusCode, NewPayload, NewHeaders}

You might use it to implement a custom compression or caching scheme.

Filter installation

Filter module can be installed with the `controller_filter_modules' config option:

{controller_filter_modules, [my_awesome_filter1, my_awesome_filter2]}

Filters are applied in order. For a particular controller, you can override the default filter list with the following three functions:

-module(my_awesome_controller, [Req, SessionID]).
-export([before_filters/2, middle_filters/2, after_filters/2]).

before_filters(DefaultFilters, RequestContext) -> BeforeFilters
middle_filters(DefaultFilters, RequestContext) -> MiddleFilters
after_filters(DefaultFilters, RequestContext) -> AfterFilters

That way you can rearrange, insert, or delete filters based on the current request.

For now just put filter modules into your project's "lib" directory.

Filter configuration

The `FilterConfig' argument passed to the filter functions is set in your boss.config and can be overridden by the controllers.

To set a default config value for `my_awesome_filter' in your boss.config:

{boss, [
    {controller_filter_config, [
        {my_awesome_filter, [{awesomeness, 100}]}
        ]}
    ]}

Then to override the value for a given request, export a `config/2' function from your controller:

-module(my_cool_controller, [Req, SessionId]).
-export([config/2]).

config(my_awesome_filter, _DefaultValue, RequestContext) ->
    [{awesomeness, 200}].

The first argument is the name of the filter. It will either be the name of filter module itself or a short name provided by the filter. Short names can be shared by multiple filters, in which case they will receive the same config value.

Setting a short name and default config value

Filter modules can export two functions to set a short name for themselves and to provide a default config value:

-module(my_awesome_filter).
-export([config_key/0, config_default_value/0]).

config_key() -> 'awesome'.
config_default_value() -> [{awesomeness, 50}].

Accessing the request context

If a controller action function takes three arguments, the request context proplist will be passed in as the third argument.