That question was already asked in 2010, but I figure there might be a better answer today. Basically I need to store some kind of object and access it in every request, ideally I want to be able to change that object from within a request (I guess an MVar or IORef will do for that).
The snaplet tutorial seems to indicate that it's possible, but it mostly explains how to use snaplets (that's what that tutorial is for after all), and doesn't really explain how this "App" object works or even is stored. I have no idea how to apply that to my case, where I have no need of snaplets (I'm making an API, so I don't even need Heist).
So given the default code :
site :: Snap ()
site = do
ifTop (writeBS "hello world") <|>
route [ ("stuff/:param", someHandler) ] <|>
dir "static" (serveDirectory ".")
How do I change this to "register" some object somewhere that I could use in someHandler ? The answer from 2010 is just to partially apply it to every handler, which would work, but the Snaplet tutorial makes me think there must be a better way.
In the section "Working with State" in the snaplet tutorial they explain how to work with local state. If you look at the second code piece in the section called "Snaplet Overview" above that, you can see how they're setting up the state when they initialise the data type for it, using Lens.
Not sure how familiar you are with these things, but Lens
lets you access (ie read/write/adjust) pieces of data within larger values. The entire state of the server in this case is represented as one blob of data (a record type value), which is initialised when the server is.
Note this: _companyName :: IORef B.ByteString
<- is a piece of state that you can mutate in the example, and in the section "Working with state" that's just what they do. They have an example that takes an HTTP GET or POST to that URL, and either updates it with the new "name" param (POST) and returns the new state, or if it's a GET, it just returns the current state.