The Chicago Boss API is mostly stable, but still might change before 1.0.
Jump to: Routes Authorization Return values Caching Content-Language Post-processing SimpleBridge request object
Chicago Boss associates each URL with a function of a controller.
The URL foo_controller:bar
.
Each controller module should go into your project's src/controller/ directory and the file name should start with the application name and end with "_controller.erl", e.g. "appname_my_controller.erl".
Helper functions should go into your project's src/lib/ directory.
Controllers can take one parameter or two parameters: the SimpleBridge request object, and an optional session ID (if sessions are enabled). Declare it like:
Or:
Each exported controller function takes two or three arguments:
'GET'
or 'POST'
before_
in the controllerExample function clauses:
These function clauses act as templates for constructing URLs in the view; for each CamelCase variable, simply use the lower-cased underscored equivalent as the parameter name. To continue the example above, you can construct URLs to match the above controllers with the following view tags:
Template variables can of course be used in place of string literals.
Most routing takes place in the controller pattern-matching code. You can define additional routes in priv/my_application.routes
. The file contains a list of erlang terms, one per line finished with a dot. Each term is a tuple with a URL or an HTTP status code as the first term, and a Location::proplist()
as the second term.
The Location
proplist must contain keys for controller
and action
. An optional application
key will route requests across applications.
A few examples of routes:
Most routes directly render the specified action; however, routing across applications (as in the second example) results in a 302 redirect. Note that the {% url %}
template tag will use the routes file to generate "pretty" URLs where appropriate.
Additional Location
parameters will be matched against the variable names of the controller's token list. For example, if user_controller.erl
contains:
Then the location [{controller, "user"}, {action, "profile"}, {user_id, "123"}]
will invoke the "profile" action of user_controller
and pass in "123" as the only token (that is, UserId
). If a location parameter does not match any variables in the token list, it will be passed in as a query parameter (e.g. ?user_id=123
).
Routing URLs may contain regular expresssions. For example, the following route will match all URLs that start with a digit:
Sub-expressions can be captured using parentheses and substituted with the atoms '$1'
, '$2'
, etc. For example, the following route will capture a string of digits and pass them in as the coupon_id
parameter:
Alternatively, named groups may be used to identify captured sub-expressions. For example, the following route is equivalent to the one above:
The route expressions must match the entire URL. That is, the expressions are implicitly bookended with ^ and $.
To define a default action for a controller, simply add a default_action
attribute to the controller like so:
If an action takes three arguments, then the function before_/3
in your controller will be passed:
before_/3
should return one of:
ExtraInfo
will be passed as the third argument to the action, and as a variable called "_before" to the templates.
Location = string() | [{Key::atom(), Value::atom()}]
Do not execute the action. Instead, perform a 302 redirect to Location
, which can be a string or a proplist that will be converted to a URL using the routes system.
Probably most common before_/3
looks like:
before_(_, _, _) -> my_user_lib:require_login(Req).
Which might return a tuple of user credential or else redirect to a login page. This way, if you want to require a login to a set of actions, just give those actions a User
argument, and the actions will be login protected and have access to the User
variable.
Whether or not it takes a third argument, a controller action should return with one of the following:
The template will be rendered without any variables.
Variables
will be passed into the associated Django template.
Variables
will be passed into the associated Django template, and Headers
are HTTP headers you want to set (e.g., Content-Type
).
The template will be rendered without any variables and served as Content-Type: application/javascript
.
Variables
will be passed into the associated Django template and the result will be served as Content-Type: application/javascript
.
Variables
will be passed into the associated Django template, the result served as Content-Type: application/javascript
, and Headers
are HTTP headers you want to set.
Location = string() | [{action, Value::string()}, ...]
Perform a 302 HTTP redirect to Location
, which may be a URL string or a proplist of parameters that will be converted to a URL using the routes system.
Perform a 302 HTTP redirect to Location
and set additional HTTP Headers
.
Location = string() | [{action, Value::string()}, ...]
Perform a 301 HTTP redirect to Location
, which may be a URL string or a proplist of parameters that will be converted to a URL using the routes system.
Perform a 301 HTTP redirect to Location
and set additional HTTP Headers
.
OtherLocation = [{action, Value::string()}, ...]
Execute the controller action specified by OtherLocation
, but without performing an HTTP redirect.
OtherLocation = [{action, Value::string()}, ...]
Render the view from OtherLocation
, but don't actually execute the associated controller action.
Render the view from OtherLocation
using Variables
, but don't actually execute the associated controller action.
Skip views altogether and return Output
to the client.
Skip views altogether and return Output
to the client while setting additional HTTP Headers
.
Stream a response to the client using HTTP chunked encoding. For each chunk, the Generator
function is passed an accumulator (initally Acc0
) and should return either {output, Data, Acc1}
or done
.
Same as above, but set additional HTTP Headers
.
Return Data
as a JSON object to the client. Performs appropriate serialization if the values in Data contain a BossRecord or a list of BossRecords.
Return Data
to the client as a JSON object while setting additional HTTP Headers
.
Returns Data
as a JSONP method call to the client. Performs appropriate serialization if the values in Data contain a BossRecord or a list of BossRecords.
Return Data
to the client as a JSONP method call (as above) while setting additional HTTP Headers
.
Invoke the 404 File Not Found handler.
Return an arbitary HTTP integer StatusCode
along with a Body
and additional HTTP Headers
.
Caching should be a part of any scalability strategy. In addition to caching the results of database queries (see config), Chicago Boss can cache the list of variables returned from controller actions. CB can also cache entire rendered web pages, but in doing so you will lose the benefit of customizing the page contents with the _before
variable, which is not cached.
To enable caching, first make sure the cache_enable
is set to true
in your configuration and that you've configured cache servers. At present only Memcached cache servers are supported, but additional adapters will be added in the future.
Next, define a cache_
function with the following arguments:
Action
- the action name (a string)Tokens
- a list of tokensAuthInfo
(optional) - authorization information returned from the before_
filter (see Authorization)The cache_
function should return one of:
{vars, CacheOptions}
- cache the variable list returned by the controller action{page, CacheOptions}
- cache the rendered page contentsnone
- don't cacheFinally, CacheOptions
is a proplist possibly containing:
seconds
- length of time to cache the result, in secondswatch
- a topic string defining a collection of records to watch for changes. When a change is observed, the cached data will be invalidatedNote that separate cache entries are created for each language as returned by lang_
(see Content-Language).
Example cache_
function:
CB application views can be multi-lingual. By default, the language served to the client is chosen by comparing the incoming Accept-Language header to the available translations in a given view (see "How Chicago Boss Chooses Which Language To Serve". This can be overridden in two ways:
lang_
function in your controller which returns the chosen language
The lang_
function will be passed the name of the current action, and optionally the result of the before_
filter. This function should return one of:
auto
- automatically choose a language based on the Accept-Language header
If it exists, a function called after_
in your controller will be passed the result that is about to be returned to the client. The 'after_' function takes two or three arguments:
The after_
function should return a (possibly) modified HTTP result tuple. Result tuples may be one of:
Performs a 302 HTTP redirect to Location
and sets additional HTTP Headers
.
Returns a 200 OK response to the client with Payload
as the HTTP body, and sets additional HTTP Headers
.
Returns a 401 Unauthorized response to the client with Payload
as the HTTP body, and sets additional HTTP Headers
.
Returns a 404 Not Found response to the client with Payload
as the HTTP body, and sets additional HTTP Headers
.
Returns a 500 Internal Error response to the client with Payload
as the HTTP body, and sets additional HTTP Headers
.
Controller functions are passed a SimpleBridge request object (slightly modified for Boss's purposes). Useful functions in the request object include:
Get the request method, e.g. GET, POST, etc.
Get the request protocol (HTTP or HTTPS).
Get the IP Address of the connected client as a 4-tuple for IPv4 or an 8-tuple for IPv6 (e.g. {127, 0, 0, 1}
)
Get the value of a given query string parameter (e.g. "?id=1234")
Get the value of a given POST parameter.
Get the value of a given POST/GET parameter.
Get the value of a given "deep" POST parameter. This function parses parameters that have numerical or labeled indices, such as "widget[4][name]", and returns either a value or a set of nested lists (for numerical indices) and proplists (for string indices).
Get the value of a given HTTP request header. Valid Header
values are strings or one of these atoms:
accept
accept_language
accept_ranges
authorization
connection
content_encoding
content_length
content_type
cookie
host
if_match
if_modified_since
if_none_match
if_unmodified_since
keep_alive
location
range
referer
transfer_encoding
user_agent
x_forwarded_for
Get the value of a given cookie.