-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | A functional web framework. -- -- A Haskell web framework where you write plain old functions. -- -- Provided you have stack installed, you can run this -- example like a shell script (it'll listen on port 3000): -- --
--   #!/usr/bin/env stack
--   -- stack --resolver lts-5.5 --install-ghc runghc --package fn --package warp
--   {-# LANGUAGE OverloadedStrings #-}
--   import Data.Monoid ((<>))
--   import Data.Text (Text)
--   import Network.Wai (Response)
--   import Network.Wai.Handler.Warp (run)
--   import Web.Fn
--   
--   data Ctxt = Ctxt { _req :: FnRequest }
--   instance RequestContext Ctxt where
--     getRequest = _req
--     setRequest c r = c { _req = r }
--   
--   initializer :: IO Ctxt
--   initializer = return (Ctxt defaultFnRequest)
--   
--   main :: IO ()
--   main = do ctxt <- initializer
--             run 3000 $ toWAI ctxt site
--   
--   site :: Ctxt -> IO Response
--   site ctxt = route ctxt [ end                        ==> indexH
--                          , path "echo" // param "msg" ==> echoH
--                          , path "echo" // segment     ==> echoH
--                          ]
--                     `fallthrough` notFoundText "Page not found."
--   
--   indexH :: Ctxt -> IO (Maybe Response)
--   indexH _ = okText "Try visiting /echo?msg=hello or /echo/hello"
--   
--   echoH :: Ctxt -> Text -> IO (Maybe Response)
--   echoH _ msg = okText $ "Echoing '" <> msg <> "'."
--   
-- -- Fn lets you write web code that just looks like normal Haskell code. -- -- -- -- The name comes from the fact that Fn emphasizes functions (over -- monads), where all necessary data is passed via function arguments, -- and control flow is mediated by return values. @package fn @version 0.3.0.2 -- | This package provides a simple framework for routing and responses. -- The two primary goals are: -- --
    --
  1. All web handler functions are just plain IO. There is no Fn monad, -- or monad transformer. This has a lot of nice properties, foremost -- among them is that it is easier to call handlers from other contexts -- (like GHCi, when testing, in other threads, etc). As a result, these -- functions take a single extra parameter that has the context that they -- need (like database connection pools, the request, etc).
  2. --
  3. Web handlers are functions with typed parameters. When routing, we -- specify many parameters (most commonly, numeric ids, but can be many -- things), so the handlers should be functions that take those as -- parameters.
  4. --
module Web.Fn -- | A normal WAI Request and the parsed post body (if present). We -- can only parse the body once, so we need to have our request (which we -- pass around) to be able to have the parsed body. type FnRequest = (Request, PostMVar) -- | A default request, which is a WAI defaultRequest and a place for an -- MVar where post info will be placed (if you parse the post body). -- -- Warning: If you try to parse the post body (with !=>) -- without replacing the Nothing placeholder with an actual MVar, it will -- blow up! defaultFnRequest :: FnRequest -- | Specify the way that Fn can get the FnRequest out of your -- context. -- -- The easiest way to instantiate this is to use the lens, but if you -- don't want to use lenses, define getRequest and -- setRequest. -- -- Note that requestLens is defined in terms of getRequest -- and setRequest and vice-versa, so you need to define _one_ of -- these. class RequestContext ctxt where requestLens f c = setRequest c <$> f (getRequest c) getRequest c = let (Store r _) = requestLens (`Store` id) c in r setRequest c r = let (Store _ b) = requestLens (`Store` id) c in b r requestLens :: (RequestContext ctxt, Functor f) => (FnRequest -> f FnRequest) -> ctxt -> f ctxt getRequest :: RequestContext ctxt => ctxt -> FnRequest setRequest :: RequestContext ctxt => ctxt -> FnRequest -> ctxt -- | Convert an Fn application (provide a context, a context to response -- function and we'll create a WAI application by updating the -- FnRequest value for each call). toWAI :: RequestContext ctxt => ctxt -> (ctxt -> IO Response) -> Application -- | The parts of the path, when split on /, and the query. type Req = (Request, [Text], Query, StdMethod, PostMVar) -- | The type of a route, constructed with 'pattern ==> handler'. type Route ctxt = ctxt -> Req -> IO (Maybe (IO (Maybe Response))) -- | The main construct for Fn, route takes a context (which it will -- pass to all handlers) and a list of potential matches (which, once -- they match, may still end up deciding not to handle the request - -- hence the double Maybe). It can be nested. -- --
--   app c = route c [ end ==> index
--                   , path "foo" // path "bar" // segment /? param "id ==> h]
--     where index :: Ctxt -> IO (Maybe Response)
--           index _ = okText "This is the index."
--           h :: Ctxt -> Text -> Text -> IO (Maybe Response)
--           h _ s i = okText ("got path /foo/" <> s <> ", with id=" <> i)
--   
route :: RequestContext ctxt => ctxt -> [Route ctxt] -> IO (Maybe Response) -- | The route function (and all your handlers) return 'IO (Maybe -- Response)', because each can elect to not respond (in which case we -- will continue to match on routes). But to construct an application, we -- need a response in the case that nothing matched - this is what -- fallthrough allows you to specify. In particular, -- notFoundText and notFoundHtml may be useful. fallthrough :: IO (Maybe Response) -> IO Response -> IO Response -- | The non-body parsing connective between route patterns and the handler -- that will be called if the pattern matches. The type is not -- particularly illuminating, as it uses polymorphism to be able to match -- route patterns with varying numbers (and types) of parts with -- functions of the corresponding number of arguments and types. (==>) :: RequestContext ctxt => (Req -> IO (Maybe (Req, k -> a))) -> (ctxt -> k) -> ctxt -> Req -> IO (Maybe a) -- | The connective between route patterns and the handler that parses the -- body, which allows post params to be extracted with param and -- allows file to work (otherwise, it will trigger a runtime -- error). (!=>) :: RequestContext ctxt => (Req -> IO (Maybe (Req, k -> a))) -> (ctxt -> k) -> ctxt -> Req -> IO (Maybe a) -- | Connects two path segments. Note that when normally used, the type -- parameter r is Req. It is more general here to facilitate -- testing. (//) :: (r -> IO (Maybe (r, k -> k'))) -> (r -> IO (Maybe (r, k' -> a))) -> r -> IO (Maybe (r, k -> a)) -- | A synonym for //. To be removed -- | Deprecated: Use the identical // instead. (/?) :: (r -> IO (Maybe (r, k -> k'))) -> (r -> IO (Maybe (r, k' -> a))) -> r -> IO (Maybe (r, k -> a)) -- | Matches a literal part of the path. If there is no path part left, or -- the next part does not match, the whole match fails. path :: Text -> Req -> IO (Maybe (Req, a -> a)) -- | Matches there being no parts of the path left. This is useful when -- matching index routes. end :: Req -> IO (Maybe (Req, a -> a)) -- | Matches anything. anything :: Req -> IO (Maybe (Req, a -> a)) -- | Captures a part of the path. It will parse the part into the type -- specified by the handler it is matched to. If there is no segment, or -- if the segment cannot be parsed as such, it won't match. segment :: FromParam p => Req -> IO (Maybe (Req, (p -> a) -> a)) -- | Matches on a particular HTTP method. method :: StdMethod -> Req -> IO (Maybe (Req, a -> a)) -- | A class that is used for parsing for param and paramOpt. -- and segment. class FromParam a fromParam :: FromParam a => [Text] -> Either ParamError a data ParamError ParamMissing :: ParamError ParamTooMany :: ParamError ParamUnparsable :: ParamError ParamOtherError :: Text -> ParamError -- | Matches on a query parameter of the given name. It is parsed into the -- type needed by the handler, which can be a Maybe type if the -- parameter is optional, or a list type if there can be many. If the -- parameters cannot be parsed into the type needed by the handler, it -- won't match. -- -- Note: If you have used the !=> connective, so that the -- request body has been parsed, this will also match post parameters -- (and will combine the two together). If you haven't used that -- connective (so the pattern is matched to handler with ==>), -- it will only match query parameters. param :: FromParam p => Text -> Req -> IO (Maybe (Req, (p -> a) -> a)) -- | Matches on query parameters of the given name. If there are no -- parameters, or they cannot be parsed into the type needed by the -- handler, it won't match. -- | Deprecated: Use param with a list type, or define param -- parsing for non-empty list. paramMany :: FromParam p => Text -> Req -> IO (Maybe (Req, ([p] -> a) -> a)) -- | If the specified parameters are present, they will be parsed into the -- type needed by the handler, but if they aren't present or cannot be -- parsed, the handler will still be called. -- -- Note: If you have used the !=> connective, so that the -- request body has been parsed, this will also match post parameters -- (and will combine the two together). If you haven't used that -- connective (so the pattern is matched to handler with ==>), -- it will only match query parameters. paramOpt :: FromParam p => Text -> Req -> IO (Maybe (Req, (Either ParamError p -> a) -> a)) -- | An uploaded file. data File File :: Text -> Text -> FilePath -> File [fileName] :: File -> Text [fileContentType] :: File -> Text [filePath] :: File -> FilePath -- | Matches an uploaded file with the given parameter name. file :: Text -> Req -> IO (Maybe (Req, (File -> a) -> a)) -- | Matches all uploaded files, passing their parameter names and -- contents. files :: Req -> IO (Maybe (Req, ([(Text, File)] -> a) -> a)) -- | Serves static files out of the specified path according to the request -- path. Note that if you have matched parts of the path, those will not -- be included in the path used to find the static file. For example, if -- you have a file static/img/a.png, and do: -- --
--   path "img" ==> staticServe "static"
--   
-- -- It will match img/img/a.png, not img/a.png. If you -- wanted that, you could: -- --
--   anything ==> staticServe "static"
--   
-- -- If no file is found, or if the path has .. or starts with -- /, this will continue routing. staticServe :: RequestContext ctxt => Text -> ctxt -> IO (Maybe Response) -- | Sends a specific file specified by path. It will specify the -- content-type if it can figure it out by the file extension. -- -- If no file exists at the given path, it will keep routing. sendFile :: FilePath -> IO (Maybe Response) -- | Returns Text as a response. okText :: Text -> IO (Maybe Response) -- | Returns Text as a JSON response with appropriate header. okJson :: Text -> IO (Maybe Response) -- | Returns Html (in Text) as a response. okHtml :: Text -> IO (Maybe Response) -- | Returns Text as a response with a 500 status code. errText :: Text -> IO (Maybe Response) -- | Returns Html (in Text) as a response with a 500 status code. errHtml :: Text -> IO (Maybe Response) -- | Returns a 404 with the given Text as a body. Note that this -- returns a 'IO Response' not an 'IO (Maybe Response)' because the -- expectaiton is that you are calling this with fallthrough. notFoundText :: Text -> IO Response -- | Returns a 404 with the given html as a body. Note that this returns a -- 'IO Response' not an 'IO (Maybe Response)' because the expectaiton is -- that you are calling this with fallthrough. notFoundHtml :: Text -> IO Response -- | Redirects to the given url. Note that the target is not validated, so -- it should be an absolute path/url. redirect :: Text -> IO (Maybe Response) -- | Redirects to the referrer, if present in headers, else to "/". redirectReferer :: RequestContext ctxt => ctxt -> IO (Maybe Response) -- | Internal helper - uses the name of the file as the pattern. tempFileBackEnd' :: InternalState -> ignored1 -> FileInfo () -> IO ByteString -> IO FilePath instance GHC.Show.Show Web.Fn.ParamError instance GHC.Classes.Eq Web.Fn.ParamError instance GHC.Base.Functor (Web.Fn.Store b) instance Web.Fn.RequestContext Web.Fn.FnRequest instance Web.Fn.FromParam Data.Text.Internal.Text instance Web.Fn.FromParam GHC.Types.Int instance Web.Fn.FromParam GHC.Types.Double instance Web.Fn.FromParam a => Web.Fn.FromParam [a] instance Web.Fn.FromParam a => Web.Fn.FromParam (GHC.Base.Maybe a)