EllaSource codeContentsIndex
Ella.Framework
Contents
Dispatching
Defaults
Routing mechanism
Matchers
Synopsis
dispatchCGI :: [View] -> DispatchOptions -> IO ()
sendResponseCGI :: Response -> IO ()
dispatchRequest :: [View] -> View
data DispatchOptions = DispatchOptions {
notFoundHandler :: View
requestOptions :: RequestOptions
viewProcessors :: [View -> View]
}
defaultDispatchOptions :: DispatchOptions
defaultRequestOptions :: RequestOptions
default404 :: Response
default500 :: String -> Response
type View = Request -> IO (Maybe Response)
route :: (PartMatch a -> Maybe (PartMatch View)) -> a -> [View -> View] -> View
(//->) :: (PartMatch a -> Maybe (PartMatch View)) -> a -> [View -> View] -> Request -> IO (Maybe Response)
type PartMatch a = (String, a, Request)
fixedString :: String -> PartMatch a -> Maybe (PartMatch a)
anyParam :: Param t => PartMatch (t -> a) -> Maybe (PartMatch a)
intParam :: PartMatch (Int -> a) -> Maybe (PartMatch a)
stringParam :: PartMatch (String -> a) -> Maybe (PartMatch a)
anyPath :: PartMatch a -> Maybe (PartMatch a)
empty :: PartMatch a -> Maybe (PartMatch a)
(</>) :: (PartMatch a -> Maybe (PartMatch b)) -> (PartMatch b -> Maybe (PartMatch c)) -> PartMatch a -> Maybe (PartMatch c)
(</+>) :: (PartMatch a -> Maybe (PartMatch b)) -> String -> PartMatch a -> Maybe (PartMatch b)
(<+/>) :: String -> (PartMatch a -> Maybe (PartMatch b)) -> PartMatch a -> Maybe (PartMatch b)
Dispatching

The main entry point for handling CGI requests is dispatchCGI. This creates a Request object according to the CGI protocol, dispatches it to a list of views, returning a 404 if no view matches. This process can be customised using DispatchOptions. A set of defaults for this is provided, defaultDispatchOptions, which can be used as a starting point and customised as needed.

dispatchCGI does not do any error handling. Since the type of any error handling function will depend on the libraries being used, it is easier to wrap the call to dispatchCGI in your own error handling. For finer grained error handling, view decorator functions can be used, as well as error handling within the view function itself.

dispatchCGISource
:: [View]list of views functions that will be tried in order
-> DispatchOptionsoptions to use in dispatching
-> IO ()
Handle a CGI request using a list of possible views If a view returns Nothing the next will be tried, and a 404 issued if all return nothing
sendResponseCGI :: Response -> IO ()Source
Sends a Response according to the CGI protocol
dispatchRequest :: [View] -> ViewSource

Used by dispatchCGI, might be useful on its own, especially in testing

Effectively this reduces a list of view functions so that they act as a single one

data DispatchOptions Source
Options for the dispatch process
Constructors
DispatchOptions
notFoundHandler :: Viewfunction that will return a 404 page in the case of no view functions matching. It is defined as View for simplicity - it should always return Just something.
requestOptions :: RequestOptionsoptions passed to buildCGIRequest
viewProcessors :: [View -> View]view processors that should be applied to list of views.
Defaults
defaultDispatchOptions :: DispatchOptionsSource
A set of DispatchOptions useful as a basis.
defaultRequestOptions :: RequestOptionsSource
Default options used for interpreting the request
default404 :: ResponseSource
A basic 404 response that is used by defaultDispatchOptions
default500 :: String -> ResponseSource
A basic 500 response, not used internally.
Routing mechanism
type View = Request -> IO (Maybe Response)Source

The routing mechanism has been designed so that you can write code like the following:

 routes :: [View]
 routes = [
            empty                                  //-> indexView                 $ decs
          , "posts/" <+/> empty                    //-> postsView                 $ []
          , intParam                               //-> viewWithIntParam          $ []
          , stringParam                            //-> viewWithStringParam       $ []
          , intParam </+> "test/"                  //-> viewWithIntParam          $ []
          , "test/" <+/> intParam                  //-> viewWithIntParam          $ []
          , anyParam </> anyParam                  //-> viewWithIntAndStringParam $ []
          , intParam </> stringParam </> intParam  //-> viewWithIntStringInt      $ []
          ]

where:

  postsView, indexView :: Request -> IO (Maybe Response)  (i.e. View)
  viewWithStringParam :: String -> Request -> IO (Maybe Response)
  viewWithIntParam :: Int -> Request -> IO (Maybe Response)
  viewWithIntAndStringParam :: Int -> String -> Request -> IO (Maybe Response)
  viewWithIntStringInt :: Int -> String -> Int -> Request -> IO (Maybe Response)
  decs :: [View -> View]

These would correspond to URLs like the following:

 /
 /posts/
 /123/             123 captured
 /abc7/            "abc7" captured
 /123/test/        123 captured
 /test/123/        123 captured
 /123/abc7/        123 and "abc7" captured
 /123/abc7/456/    123, "abc7" and 456 captured

The right hand argument of //-> is a 'view like' function, of type View OR a -> View OR a -> b -> View etc,

The left hand argument of //-> is a 'matcher' - it parses the path of the Request, optionally capturing parameters and returning a function that will adapt the right hand argument so that it has type View.

Matchers can be composed using </>. To match a fixed string without capturing, use fixedString thestring. The operators </+> amd <+/> are useful for combining fixed strings with other matchers. To match just a fixed string, you can use

 "thestring/" <+/> empty

instead of:

 fixedString "thestring/"

The result of the //-> operator needs to be applied to a list of 'view decorator' functions, (which may be an empty list) e.g. 'decs' above. These decorators take a View and return a View, or alternatively they can be considered to take a View and a Request and return an IO (Maybe Response). These means they can be used to do pre-processing of the request, and post-processing of the response.

The routing mechanism is extensible in the types of parameters that can be captured. The easiest way is to define instances of Param, and then use anyParam. For more complex needs, for example if you do not want the component to end in a forward slash, just define your own matchers.

When defining routes as above, choosing anyParam instead of intParam or stringParam will produce exactly the same result. With anyParam, the type will be determined by type inference. With stringParam etc., you are repeating the type information, which is a DRY violation, but it may be useful for clarity, and you will get a compilation error in the case of any mismatch.

NB. The Request object trims any leading slash on the path to normalise it, and also to simplify this parsing stage, so do not attempt to match an initial leading slash.

routeSource
::
=> PartMatch a -> Maybe (PartMatch View)matcher
-> aview-like function
-> [View -> View]optional view decorators (processors)
-> View
Apply a matcher to a View (or View-like function that takes additional parameters) to get a View that only responds to the matched URLs
(//->) :: (PartMatch a -> Maybe (PartMatch View)) -> a -> [View -> View] -> Request -> IO (Maybe Response)Source
Alias for route, see above examples.
Matchers
type PartMatch a = (String, a, Request)Source
type alias used to simplify signatures

Matching functions take a PartMatch and return a Maybe PartMatch. The first component of PartMatch is a String which is the remaining part of the pathInfo still to be matched.

The second component of PartMatch is a View function, or a function that returns a View when partially applied. This allows for matchers that also capture parameters (of different types) and feed them to the view functions. In this case, the PartMatch output will have a different type to the PartMatch input.

The third component of PartMatch is the entire Request object. This allows matchers to operate on other attributes of the Request e.g. only match GET requests. It also allows them to alter the Request object that a view function receives.

fixedString :: String -> PartMatch a -> Maybe (PartMatch a)Source
Match a string at the beginning of the path
anyParam :: Param t => PartMatch (t -> a) -> Maybe (PartMatch a)Source

Matcher that matches any instance of Param followed by a forward slash.

If anyParam is used, the concrete type will be determined by type inference from the view function.

intParam :: PartMatch (Int -> a) -> Maybe (PartMatch a)Source

Matcher that captures an integer component followed by a forward slash

This is anyParam specialised to ints

stringParam :: PartMatch (String -> a) -> Maybe (PartMatch a)Source

Matcher that captures a string component followed by a forward slash

This is anyParam specialised to strings

anyPath :: PartMatch a -> Maybe (PartMatch a)Source
Matcher that matches any remaining path
empty :: PartMatch a -> Maybe (PartMatch a)Source
Convenience no-op matcher, useful for when you only want to match a fixed string, or to match an empty string.
(</>)Source
::
=> PartMatch a -> Maybe (PartMatch b)LH matcher
-> PartMatch b -> Maybe (PartMatch c)RH matcher
-> PartMatch a -> Maybe (PartMatch c)
Combine two matchers
(</+>)Source
::
=> PartMatch a -> Maybe (PartMatch b)matcher
-> Stringfixed string
-> PartMatch a -> Maybe (PartMatch b)
Convenience operator for combining a fixed string after a matcher
(<+/>)Source
::
=> Stringfixed string
-> PartMatch a -> Maybe (PartMatch b)matcher
-> PartMatch a -> Maybe (PartMatch b)
Convenience operator for combining a matcher after a fixed string
Produced by Haddock version 2.4.2