Awesome
Giallo (v0.2.0)
Giallo (Italian pronunciation: [ˈdʒallo], plural gialli) is an Italian 20th-century genre of literature and film, which in Italian indicates crime fiction and mystery.
Giallo is released under the terms of the MIT license
Current stable version: 0.2.0
Current α alpha version: 0.3.0
copyright 2012-2013 Kivra
Goals
Giallo aims to provide a small and flexible web framework. Giallo builds on Cowboy and provides a bare minimum to implement a basic View-Controller pattern. Yes we've removed the Model from MVC, this is not a "everything but the kitchen sink" type of framework.
Giallo can easily be embedded and provides some conveinient methods for working with Controller and Views while still giving you possibility to use standard Cowboy features when necessary.
Examples
Here's some examples that will show Giallo in action.
Getting Started
A minimal working app could look like this:
-module(minimal_handler).
-export([start/0]).
-export([hi/4]).
start() ->
giallo:start([{'_', [{"/[...]", minimal_handler, []}]}]).
hi(<<"GET">>, _PathInfo, _Extra, _Req) ->
{output, <<"Ohai!">>}.
This would map the my_handler
using standard Cowboy
Routing to the
URI http://yourserver/
. Implementing the action hi
would make
Giallo output "Ohai!" when performing a GET on /hi
or anything
below /hi/extra...
. Any Giallo action that is implemented, such as hi/4
gets precedence over the standard Cowboy Handler.
The first argument is the HTTP method being used.
The _PathInfo
argument contains any extra url fragments as binaries in a
list such as /hi/extra/path/information
would give a list like
[<<"extra">>, <<"path">>, <<"information">>]
. The exact match, i.e.
/hi
would result in an empty list, []
.
The third argument contains any extra variables that either get passed
from the cowboy dispatcher or via an other action redispatching using
action_other
or from the before_/4 function.
The Req
argument is the standard Cowboy [Request]
(https://github.com/extend/cowboy/blob/master/src/cowboy_req.erl#L128) Object.
It's an opaque record so take a look at the functions in
[cowboy_req.erl]
(https://github.com/extend/cowboy/blob/master/src/cowboy_req.erl) on how
to use it.
It's also possible to use standard Cowboy handlers and also to mix the two behaviors, i.e.
-module(default_handler).
-export([start/0]).
-export([hi/4]).
%% Standard Cowboy callback handlers
-export([init/3]).
-export([handle/2]).
-export([terminate/3]).
start() ->
giallo:start([{'_', [{"/[...]", default_handler, []}]}]).
%% Standard Cowboy callback handlers
init(_Transport, Req, []) ->
{ok, Req, undefined}.
handle(Req, State) ->
{ok, Req2} = cowboy_req:reply(200, [], <<"Hello World!">>, Req),
{ok, Req2, State}.
terminate(_Reason, _Req, _State) ->
ok.
%% Giallo handler
hi(<<"GET">>, _PathInfo, _Extra, _Req) ->
{output, <<"Ohai!">>}.
This would output "Ohai!" for the same URI's as the previous example but
for anything else it would use the standard Cowboy handle/2
function.
So any Giallo function takes precedence over Cowboy handlers.
Index action
index_/4
is a special action that can be implemented and will handle
resource listings, i.e. http://my.server/path/
. Any handler mapped to
/path/
will have it's index_
function executed. index_
functions
behave the same as any other function and can thus use templating, etc.
index_(<<"GET">>, [], _Extra, _Req) ->
{output, <<"Index listing">>}.
Templating
Giallo uses ErlyDTL for
standard templating. To dispatch a request from a Giallo controller you
return ok
, {ok, Variables}
or {ok, Variables, Headers}
. Giallo
will then render the template associated with that controller and
action. Giallo compounds the template name as <controller>_<action>
.
You control how you compile your ErlyDtl templates through rebar. Using
the erlydtl_opts
directive you can specify where to find your
templates:
{erlydtl_opts, [
{doc_root, "templates"}, % Where to find your templates
{source_ext, ".html"} % Extension on your uncomplied templates
]}.
With these ErlyDTL options you would create your templates such as
controller_action.html
Session Management
If you need Session Management you'll have to include the Giallo Session Backend.
before_ function
There's a special function which can be implemented called before_/2 which can be used to preprocess any request before dispatching to any action. This is especially useful when implementing an authentication scheme.
The function header looks like:
before_(_Action, _Req) ->
{ok, []}.
The first parameter is the Action that is to be performed after
before_
has been complete, it's supplied as an atom, i.e. action_name
.
The second parameter is the standard Req object.
Possible return values are:
{ok, Extra}
Extra will get passed as the third argument to the action and as a
variable called _before
to any template
{redirect, Location}
Redirect to the Location
effectively bypassing the Action
Return values
Here's a list of possible return values from a Giallo controller.
All return values can take an optional Req :: cowboy_req:req()
as the last
parameter. This is especially useful if you need to set anything special
to the response, like cookies, sessions, etc.
ok
Continue and render the template for the corresponding action
{ok, Variables::proplist()}
Same as above but pass Variables
to the template. Variables can then be outputted in
the template as {{ variable_name }}
{ok, Variables::proplist(), Headers::proplist()}
Same as above but also set additional HTTP Headers
{redirect, Location::binary()
Send a 302 redirect to the Location
{redirect, Location::binary(), Headers::proplist()}
Same as above but also set additional HTTP Headers
{moved, Location::binary()}
Send a 301 redirect to the Location
{moved, Location::binary(), Headers::proplist()}
Same as above but also set additional HTTP Headers
{action_other, Location::proplist()}
Possible values for Location
are [{action, your_action}, {controller, your_handler}]
.
If controller
is ommitted it will assume the current handler.
{action_other, Location::proplist(), Variables::proplist()}
Same as above but pass Variables
that can be retrieved from the
controller.
{render_other, Location::proplist()}
Render the view associated with the Action at Location
. Possible values
for Location
are [{action, your_action}, {controller, your_handler}]
.
If controller
is ommitted it will assume the current handler.
{render_other, Location::proplist(), Variables::proplist()}
Same as above but pass Variables
that can be retrieved in the
template. Possible values for Location
are
[{action, your_action}, {controller, your_handler}]
.
If controller
is ommitted it will assume the current handler.
{output, Output::binary()}
print out the Output
{output, Output::binary(), Headers::proplist()}
Same as above but also set additional HTTP Headers
{stream, Generator::function(), Acc0::any()}
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. I.e:
stream(<<"GET">>, _Pathinfo, _Extra, _Req) ->
F = fun(Acc) ->
case Acc =:= 3 of
true -> done;
false -> {output, <<"Hello\n">>, Acc+1}
end
end,
{stream, F, 0}.
{stream, Generator::function(), Acc::any(), Headers::proplist()}
Same as above but also set additional HTTP Headers
{json, Data::proplist()}
Encode the Data
as json and output
{json, Data::proplist(), Headers::proplist()}
Same as above but also set additional HTTP Headers
{jsonp, Callback::string(), Data::proplist()}
Encode the Data
as valid jsonp using the Callback
{jsonp, Callback::string(), Data::proplist(), Headers::proplist()}
Same as above but also set additional HTTP Headers
not_found
Respond with a 404
{error, Status::integer()}
Respond with the given error Status Code
Request processing
There is some conventience-functions for working with headers, querystrings, multipart-data, etc. Please generate and look at the docs:
make doc
License
It's the MIT license. So go ahead and do what you want!