Jump to content
Main menu
Main menu
move to sidebar
hide
Navigation
Haskell
Wiki community
Recent changes
Random page
HaskellWiki
Search
Search
Create account
Log in
Personal tools
Create account
Log in
Pages for logged out editors
learn more
Contributions
Talk
Editing
HAppS tutorial
(section)
Page
Discussion
English
Read
Edit
View history
Tools
Tools
move to sidebar
hide
Actions
Read
Edit
View history
General
What links here
Related changes
Special pages
Page information
Warning:
You are not logged in. Your IP address will be publicly visible if you make any edits. If you
log in
or
create an account
, your edits will be attributed to your username, along with other benefits.
Anti-spam check. Do
not
fill this in!
== How to structure your handlers? == As we have discussed before, HAppS programs are structured as lists of server parts that handle events. The type system stops you from making some mistakes, but the types involved are somewhat complex to understand at first. You can get a long way by re-using the example code, but here are some tips for when it gets more elaborate. We've already seen examples of nesting with 'multi' and 'hs'. === ServerPart === <haskell> data ServerPart m req m' res = Handle (req -> m (Either req (m' res))) | ModResp (m (res -> m' res)) | Multi [ServerPart m req m' res] stdHTTP :: (MonadIO m, StartStateEx st st, Serialize st) => [ServerPart (Ev st Request) Request IO Result] -> m () </haskell> The list you give to stdHTTP is a list of ServerParts. Each ServerPart is a Handle which takes a Request, a ModResp which post-processes a further Result, or a Multi which nests more ServerParts. Of course the ServerParts can be constructed by functions so you don't have to write them manually. The normal way to construct a Handle is 'h' which makes the handler list useful by choosing which requests are handled by which handlers. For ModResp, there's a corresponding 'hOut'. 'multi' isn't very useful, it just lets you define a part as a list of parts. 'multiIf' works more like 'h', letting you filter the requests that reach the nested list. === h === <haskell> h :: (Monad m, Monad m', FromMessage req_msg, FromReqURI uri_match uri_msg, MatchMethod req_match) => uri_match -> req_match -> (uri_msg -> req_msg -> m (Either Request (m' res))) -> ServerPart m Request m' res </haskell> When you use 'h' to construct a ServerPart, you give it two expressions: one for matching the URI paths and another for matching the HTTP methods that you want the handler to handle. The third parameter is the handler itself: it gets one argument based on the URI and another based on the query parameters. The type classes FromMessage, FromReqURI and MatchMethod ensure that there are various types uri_match, req_match, uri_msg and req_msg can take, and you can define more. === hs === <haskell> hs :: path -> method -> (path -> method -> res) -> res basicFileServe :: (FromReqURI urimatcher [String], HAppS.Protocols.SimpleHTTP2.MatchMethod matcher, Monad m) => String -> urimatcher -> matcher -> ServerPart m Request IO Result </haskell> As can be seen from the extremely generic type, 'hs' doesn't really do anything. From the earlier examples we have learned that it lets us include in our part list a part which does its own filtering and message decoding, such as basicFileServe, so that it looks like a call to 'h'. It doesn't do any actual request filtering, it just passes the filtering expressions to the part. === multiIf === <haskell> multiIf :: (MatchMethod req_match, FromReqURI uri_match (), Monad m, Monad m') => uri_match -> req_match -> [ServerPart m Request m' res] -> ServerPart m Request m' res </haskell> An interesting variation of 'h', 'multiIf' takes URI path and HTTP method matching expressions, and excludes non-matching requests from a nested list of server parts. For example, [http://hpaste.org/ HPaste] includes a ServerPart called adminSubsystem [http://www.scannedinavian.com/~eric/hpaste-devel/ in its source code]. It implements the URI paths that start with /admin and doesn't affect other URIs: <haskell> adminSubsystem accounts = multiIf (Prefix ["admin"]) [GET,POST] [hs () () $ basicAuth "Admins Only" accounts ,h ["admin","delete"] GET $ ok handleGetDelete ,h ["admin","delete"] POST $ seeOther handlePostDelete ,h () () $ ok handleAdminIndex ] </haskell> Here the effect of multiIf is that 'basicAuth' and 'handleAdminIndex' aren't applied to all requests. Notice how "admin" still needs to be included in the delete handlers, since 'multiIf' only filters. === runServerParts === <haskell> runServerParts :: (Monad m', Monad m) => [ServerPart m request m' response] -> request -> m (Either request (m' response)) </haskell> Lists of ServerParts are normally run with 'runServerParts'. It can be used to process a nested list of parts in a custom handler. For example, here's a handler that sets the implicit parameters ?root and ?time to be available within all of handlers in 'myApp': <haskell> h (Prefix ()) () $ \(path::[String]) req -> do time <- getTime let root = concatMap (const "../") $ drop 1 path let ?time = time; ?root = root in runServerParts myApp req </haskell> (Implicit parameters are useful when you don't want to pass the parameters explicitly in a deep hierarchy of function calls. 'getTime' needs to be run in the monad but ?time is available in pure functions. ?root provides the right amount of '..' needed in the beginning of link URI references to get to the root directory of myApp even when the HTTP server hosts more than one application, perhaps even behind an Apache reverse proxy.)
Summary:
Please note that all contributions to HaskellWiki are considered to be released under simple permissive license (see
HaskellWiki:Copyrights
for details). If you don't want your writing to be edited mercilessly and redistributed at will, then don't submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource.
DO NOT SUBMIT COPYRIGHTED WORK WITHOUT PERMISSION!
Cancel
Editing help
(opens in new window)
Toggle limited content width