A state record. It is created for each HTTP request and represents the current state of the application. It contains:
This structure is very volatile, will be updated quite often on the application's life cycle.
The main modules that update the state are:
Routes:
Add information from the matched route to the state map
Interceptors:
Add, consumes or remove information from the state map. More details in Interceptors section.
Actions:
In actions, you are able to interfere with the :leave parts of the interceptors.
At the last step of execution the handler extracts the response value from the state.
The state is renewed on every request.
"Monads are a simple and powerful mechanism for function composition that helps us to solve very common IT problems such as input/output, exception handling, parsing, concurrency and other. Application becomes less error-prone. Code becomes reusable and more readable."
And we use it to do exactly that: to add Failure/Success metadata to our internal wrapped state, our data flow unity.
Think of it as a container that's composed by metadata plus its data value. Every function that returns the state map needs to be wrapped first, to provide the right binary direction on Success or Failure.
This is done by: xiana/ok
and xiana/error
functions. Which are defined in xiana/core.clj
.
The container travels through the application and dictates how it will operate, based on the binary direction values
It's easier to get used to with the following analogy. Xiana it looks and works like railway programming: If the execution is flawless, the state successfully traverses the whole link of interceptors and action. If the execution fails at any point, the monadic system short circuits the execution. Preventing us to make any other errors.
The action conventionally is the control point of the application flow. This is the place were you can define how the rest of your execution flow would behave. Here you can provide the database query, restriction function, the view, and the additional side effect functions are you want to execute.
Actions are defined in the routes vector
["/" {:get {:action #(do something)}}]
The framework provided handler does all the processing. It runs on every request and does the following. It creates the state for every request, matches the appropriate route, executes the interceptors, handles interceptor overrides, and not-found cases. It handles websocket requests too.
Routing means selecting the actions to execute depending on the request URL, and HTTP method.
Modules can depend on external resources, configurations, as well as on other modules. These dependencies are added to the state on state creation, and defined on application startup.
An interceptor is a pair of unary functions. Each function is called with a state map and must return a state map
wrapped into a monad container. You can look at it as on an analogy to AOP's around aspect, or as on a pair of
middlewares.
Xiana provides a set of base interceptors, for the most common use cases.
Can you improve this documentation? These fine people already did:
Krisztian Gulyas, Stas Makarov & Marius A. RabenarivoEdit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close