-
Notifications
You must be signed in to change notification settings - Fork 5
Mechanics
This page describes the basic mechanics of Cowmachine from the point of view of a single incoming HTTP Request, documenting the behavior of Cowmachine through to the HTTP Response.
This is a bit different from what you might get with a "Web Framework" as we’re not going to talk about MVC, ORMs, or anything else about the rest of the shape of your application. We believe that you know better than we do how to structure your own app -- Cowmachine’s job is to help you make sure that your app’s presence on the Web is well-behaved and well-structured.
Dispatching is mapping an incoming HTTP request to a controller.
Cowmachine is Cowboy middleware that handles the request after
dispatching the request. The dispatcher MUST set the
controller
option in the Env
passed by the Cowboy middleware.
Optionally the dispatcher middleware before Cowmachine can also set the
following Env
values:
-
controller_options
a proplist with options for the controller -
site
a term describing the current vhost -
context
an initialized context record without the current req (Cowmachine will set the req element)
The controller_options
has one (optional) property that is interpreted
by Cowmachine:
-
http_status_code
an integer forcing the HTTP response status
All other option properties are ignored by Cowmachine.
The current controller and controller options can be fetched using:
cowmachine_req:controller(Context) -> module().
cowmachine_req:controller_options(Context) -> proplists:proplist().
The controller options default to the empty list []
.
If a controller function:
- crashes, or
- return with an http status >= 500, or
- throws the exception
{stop_request, HttpStatusCode, Reason}
then the request is redone with the controller_http_error
controller.
The error controller should render a result depending on the negotiated response content type.
The controller then flows through the decision core, which is
effectively just running the request through the
HTTP flowchart. At each decision point (diamond) in
the diagram, Cowmachine will determine which path to follow. In some
cases it can determine the path purely from the request data -- for
instance, the path from decision C3 depends purely on whether the
client sent an Accept header. In many cases, however, the decision is
application-specific -- the path from B10 depends on the value the
controller module returns from
allowed_methods
. Eventually the chosen path will terminate at one of
the rectangles on the diagram. At that point Cowmachine will send an
appropriate HTTP response, with the headers and body dependent on the
path through the diagram and the values returned by the controller’s
functions.
Most of the time you don’t need to worry about this big diagram, though -- just define the controller functions relevant to your app and Cowmachine will do the rest. A good understanding of this central mechanism in Cowmachine is most useful when debugging your controllers.
From the way that Cowmachine’s decision core works, it follows that Cowmachine’s HTTP behavior is transactional. Each HTTP Request is fully received, and the resulting HTTP Response is then fully constructed before being returned. This means that while Cowmachine is suitable for a great many Web applications it is not a good fit for an application that will gradually or continuously stream responses back to clients inside the context of a single HTTP Request.
A useful way to build Cowmachine applications is often just to write a
single function such as to_html
to provide the most basic of stubs;
when that function exists (or any other returned by
content_types_provided
) you can produce 200 OK
responses. After
that, you can easily extend your application’s Web behavior simply by
filling in the other controller functions as
desired.