Snaplets allow you to build web applications out of composable parts. This
allows you to build self-contained units and glue them together to make your
overall application.

A snaplet has a few moving parts, some user-defined and some provided by the
snaplet API:

each snaplet has its own configuration given to it at startup.

each snaplet is given its own directory on the filesystem, from which it
reads its configuration and in which it can store files.

each snaplet comes with an Initializer which defines how to create an
instance of the Snaplet at startup. The initializer decides how to
interpret the snaplet configuration, which URLs to handle (and how), sets
up the initial snaplet state, tells the snaplet runtime system how to
clean the snaplet up, etc.

each snaplet contains some user-defined in-memory state; for instance, a
snaplet that talks to a database might contain a reference to a connection
pool. The snaplet state is an ordinary Haskell record, with a datatype
defined by the snaplet author. The initial state record is created during
initialization and is available to snaplet Handlers when serving HTTP
requests.

NOTE: This documentation is written as a prose tutorial of the snaplets
API. Don't be scared by the fact that it's auto-generated and is filled with
type signatures. Just keep reading.

Snaplet

The heart of the snaplets infrastructure is state management. (Note: when
we say "state" here, we mean in-memory Haskell objects, not external data
storage or databases; how you deal with persisted data is up to you.) Most
nontrivial pieces of a web application need some kind of runtime state or
environment data. The datatype we use to handle this is called Snaplet:

An opaque data type holding internal snaplet configuration data. It is
exported publicly because the getOpaqueConfig function in MonadSnaplet
makes implementing new instances of MonadSnaplet more convenient.

Snaplet Helper Functions

Your web application will itself get wrapped in a Snaplet, and the
top-level user state of your application (which will likely contain other
snaplets nested inside it) will look something like this:

Transforms a lens of the type you get from makeLenses to an similar lens
that is more suitable for internal use.

Lenses

In the example above, the Foo snaplet has to be written to work with any
base state (otherwise it wouldn't be reusable!), but functions written to
work with the Foo snaplet want to be able to modify the Foo record
within the context of the base state. Given that Haskell datatypes are
pure, how do you allow for this?

which allow you to get, set, and modify a value of type b within the
context of type of type a. The data-lens package comes with a Template
Haskell function called makeLenses, which auto-magically defines a lens
for every record field having a name beginning with an underscore. In the
App example above, adding the declaration:

The coolest thing about data-lens lenses is that they compose, using
the Control.Category's generalization of the (.) operator. If the Foo
type had a field of type Quux within it with a lens quux :: Lens Foo
Quux, then you could create a lens of type Lens App Quux by composition:

Lens composition is very similar to function composition, but it gives you
a composed getter and setter at the same time.

MonadSnaplet

The primary abstraction in the snaplet infrastructure is a combination of
the reader and state monads. The state monad holds the top level
application data type (from now on referred to as the base state). The
reader monad holds a lens from the base state to the current snaplet's
state. This allows quux snaplet functions to access and modify the Quux
data structure without knowing anything about the App or Foo data
structures. It also lets other snaplets call functions from the quux
snaplet if they have the quux snaplet's lens Lens App (Snaplet Quux).
We can view our application as a tree of snaplets and other pieces of data.
The lenses are like pointers to nodes of the tree. If you have a pointer to
a node, you can access the node and all of its children without knowing
anything about the rest of the tree.

Several monads use this infrastructure. These monads need at least three
type parameters. Two for the lens type, and the standard 'a' denoting the
monad return value. You will usually see this written in type signatures as
"m b v a" or some variation. The 'm' is the type variable of the
MonadSnaplet type class. 'b' is the base state, and 'v' is the state of
the current "view" snaplet (or simply, current state).

The MonadSnaplet type class distills the essence of the operations used
with this pattern. Its functions define fundamental methods for navigating
snaplet trees.

Runs a child snaplet action in the current snaplet's context. If you
think about snaplet lenses using a filesystem path metaphor, the lens
supplied to this snaplet must be a relative path. In other words, the
lens's base state must be the same as the current snaplet.

Like with but doesn't impose the requirement that the action
being run be a descendant of the current snaplet. Using our filesystem
metaphor again, the lens for this function must be an absolute
path--it's base must be the same as the current base.

A variant of with accepting a lens from snaplet to snaplet. Unlike
the lens used in the above with function, this lens formulation has
an identity, which makes it useful in certain circumstances. The
lenses generated by makeLenses will not work with this function,
however the lens returned by getLens will.

Sets the route pattern that matched for the handler. Use this when to
override the default pattern which is the key to the alist passed to
addRoutes.

Snaplet state manipulation

MonadSnaplet instances will typically have MonadState v instances. We
provide the following convenience functions which give the equivalent to
MonadState (Snaplet v) for the less common cases where you need to work
with the Snaplet wrapper.

Gets the Snaplet v from the current snaplet's state and applies a
function to it.

Initializer

The Initializer monad is where your application's initialization happens.
Initializers are run at startup and any time a site reload is triggered.
The Initializer's job is to construct a snaplet's routes and initial state,
set up filesystem data, read config files, etc.

In order to initialize its state, a snaplet needs to initialize all the
Snaplet a state for each of its subsnaplets. The only way to construct
a Snaplet a type is by calling nestSnaplet or embedSnaplet from
within an initializer.

The path to the directory holding the snaplet's reference
filesystem content. This will almost always be the directory
returned by Cabal's getDataDir command, but it has to be passed in
because it is defined in a package-specific import. Setting this
value to Nothing doesn't preclude the snaplet from having files in
in the filesystem, it just means that they won't be copied there
automatically.

Note that you're writing your initializer code in the Initializer monad,
and makeSnaplet converts it into an opaque SnapletInit type. This allows
us to use the type system to ensure that the API is used correctly.

Runs another snaplet's initializer and returns the initialized Snaplet
value. Calling an initializer with nestSnaplet gives the nested snaplet
access to the same base state that the current snaplet has. This makes it
possible for the child snaplet to make use of functionality provided by
sibling snaplets.

Runs another snaplet's initializer and returns the initialized Snaplet
value. The difference between this and nestSnaplet is the first type
parameter in the third argument. The "v1 v1" makes the child snaplet
think that it is top-level, which means that it will not be able to use
functionality provided by snaplets included above it in the snaplet tree.
This strongly isolates the child snaplet, and allows you to eliminate the b
type variable. The embedded snaplet can still get functionality from other
snaplets, but only if it nests or embeds the snaplet itself.

Sets a snaplet's name. All snaplets have a default name set by the
snaplet author. This function allows you to override that name. You will
have to do this if you have more than one instance of the same kind of
snaplet because snaplet names must be unique. This function must
immediately surround the snaplet's initializer. For example:

Adds an IO action that modifies the current snaplet state to be run at
the end of initialization on the state that was created. This makes it
easier to allow one snaplet's state to be modified by another snaplet's
initializer. A good example of this is when a snaplet has templates that
define its views. The Heist snaplet provides the addTemplates function
which allows other snaplets to set up their own templates. addTemplates
is implemented using this function.

Initializers should use this function for all informational or error
messages to be displayed to the user. On application startup they will be
sent to the console. When executed from the reloader, they will be sent
back to the user in the HTTP response.

Routes

Snaplet initializers are also responsible for setting up any routes defined
by the snaplet. To do that you'll usually use either addRoutes or
wrapHandlers.

Handlers

Snaplet infrastructure is available during runtime request processing
through the Handler monad. There aren't very many standalone functions to
read about here, but this is deceptive. The key is in the type class
instances. Handler is an instance of MonadSnap, which means it is the
monad you will use to write all your application routes. It also has a
MonadSnaplet instance, which gives you all the functionality described
above.

This function brackets a Handler action in resource acquisition and
release. Like bracketSnap, this is provided because MonadCatchIO's
bracket function doesn't work properly in the case of a short-circuit
return from the action being bracketed.

In order to prevent confusion regarding the effects of the
aquisition and release actions on the Handler state, this function
doesn't accept Handler actions for the acquire or release actions.

This function will run the release action in all cases where the
acquire action succeeded. This includes the following behaviors
from the bracketed Snap action.