Skip to content

Referential Transparency

Marc Worrell edited this page Jul 25, 2019 · 2 revisions

Cowmachine goes to great lengths to help your controller functions be as referentially transparent as possible. By "referentially transparent" we mean that given the same input Context the function will return the same output {Result, Context} and that side effects will be insignificant from the point of view of Cowmachine's execution.

Benefits

Since controller functions are generally referentially transparent, many things are easier -- testing, debugging, and even static analysis and reasoning about your web application.

Exceptions

Application State

The passed Context always contains the Cowboy request map and the application-specific data you put in there.

Besides a Cowboy request map() the Context can also be a record. If it is a record then the first element of the record (i.e. the second tuple element as the first is the type of the record) must be the Cowboy request.

Example:

-record(mycontext, { Req :: cowboy_req:req(), foo, bar, etc }.

This record option is used by Zotonic, where the context contains information about the vhost being used and other Zotonic specific state. In Zotonic the request is actually optional, only when controllers are called then the request must be defined.

If you don't use your own record then you can use the following functions to access metadata in the cowboy request:

NewContext = cowmachine_req:set_metadata(Key, Value, Context)
SomeTerm = cowmachine_req:get_metadata(Key, Context)

The get_metadata will return undefined for undefined keys.

Streamed Body

The streamed body feature exists to allow constollers to consume or produce request/response bodies a hunk at a time without ever having the whole thing in memory. While the continuation-passing style used in the streaming API is friendly to general functional analysis, due to the necessary side-effect of reading or writing to sockets the stream bodies cannot be treated in quite the same way as other uses of the Context interface. Luckily, it is easy to inspect a Context to see if this is the case in any individual controller or request instance.

Clone this wiki locally