Safe Haskell | None |
---|
- data Resource typ = Resource {
- resourceName :: String
- resourcePieces :: [(CheckOverlap, Piece typ)]
- resourceDispatch :: Dispatch typ
- data ResourceTree typ
- = ResourceLeaf (Resource typ)
- | ResourceParent String [(CheckOverlap, Piece typ)] [ResourceTree typ]
- data Piece typ
- data Dispatch typ
- = Methods {
- methodsMulti :: Maybe typ
- methodsMethods :: [String]
- | Subsite {
- subsiteType :: typ
- subsiteFunc :: String
- = Methods {
- type CheckOverlap = Bool
- resourceMulti :: Resource typ -> Maybe typ
- resourceTreePieces :: ResourceTree typ -> [(CheckOverlap, Piece typ)]
- resourceTreeName :: ResourceTree typ -> String
- mkRenderRouteInstance :: Type -> [ResourceTree Type] -> Q [Dec]
- mkRenderRouteInstance' :: Cxt -> Type -> [ResourceTree Type] -> Q [Dec]
- mkRouteCons :: [ResourceTree Type] -> ([Con], [Dec])
- mkRenderRouteClauses :: [ResourceTree Type] -> Q [Clause]
- mkDispatchClause :: Q Exp -> Q Exp -> Q Exp -> [ResourceTree a] -> Q Clause
Data types
Resource | |
|
data ResourceTree typ Source
ResourceLeaf (Resource typ) | |
ResourceParent String [(CheckOverlap, Piece typ)] [ResourceTree typ] |
Functor ResourceTree | |
Lift t => Lift (ResourceTree t) |
Methods | |
| |
Subsite | |
|
type CheckOverlap = BoolSource
Helper functions
resourceMulti :: Resource typ -> Maybe typSource
resourceTreePieces :: ResourceTree typ -> [(CheckOverlap, Piece typ)]Source
resourceTreeName :: ResourceTree typ -> StringSource
Functions
RenderRoute
mkRenderRouteInstance :: Type -> [ResourceTree Type] -> Q [Dec]Source
Generate the RenderRoute
instance.
This includes both the Route
associated type and the
renderRoute
method. This function uses both mkRouteCons
and
mkRenderRouteClasses
.
mkRenderRouteInstance' :: Cxt -> Type -> [ResourceTree Type] -> Q [Dec]Source
A more general version of mkRenderRouteInstance
which takes an
additional context.
mkRouteCons :: [ResourceTree Type] -> ([Con], [Dec])Source
Generate the constructors of a route data type.
mkRenderRouteClauses :: [ResourceTree Type] -> Q [Clause]Source
Clauses for the renderRoute
method.
Dispatch
Dispatch
:: Q Exp | runHandler function |
-> Q Exp | dispatcher function |
-> Q Exp | fixHandler function |
-> [ResourceTree a] | |
-> Q Clause |
This function will generate a single clause that will address all
your routing needs. It takes four arguments. The fourth (a list of
Resource
s) is self-explanatory. We'll discuss the first
three. But first, let's cover the terminology.
Dispatching involves a master type and a sub type. When you dispatch to the top level type, master and sub are the same. Each time to dispatch to another subsite, the sub changes. This requires two changes:
- Getting the new sub value. This is handled via
subsiteFunc
. - Figure out a way to convert sub routes to the original master route. To address this, we keep a toMaster function, and each time we dispatch to a new subsite, we compose it with the constructor for that subsite.
Dispatching acts on two different components: the request method and a list of path pieces. If we cannot match the path pieces, we need to return a 404 response. If the path pieces match, but the method is not supported, we need to return a 405 response.
The final result of dispatch is going to be an application type. A simple example would be the WAI Application type. However, our handler functions will need more input: the master/subsite, the toMaster function, and the type-safe route. Therefore, we need to have another type, the handler type, and a function that turns a handler into an application, i.e.
runHandler :: handler sub master -> master -> sub -> Route sub -> (Route sub -> Route master) -> app
This is the first argument to our function. Note that this will almost certainly need to be a method of a typeclass, since it will want to behave differently based on the subsite.
Note that the 404 response passed in is an application, while the 405 response is a handler, since the former can't be passed the type-safe route.
In the case of a subsite, we don't directly deal with a handler function. Instead, we redispatch to the subsite, passing on the updated sub value and toMaster function, as well as any remaining, unparsed path pieces. This function looks like:
dispatcher :: master -> sub -> (Route sub -> Route master) -> app -> handler sub master -> Text -> [Text] -> app
Where the parameters mean master, sub, toMaster, 404 response, 405 response, request method and path pieces. This is the second argument of our function.
Finally, we need a way to decide which of the possible formats should the handler send the data out. Think of each URL holding an abstract object which has multiple representation (JSON, plain HTML etc). Each client might have a preference on which format it wants the abstract object in. For example, a javascript making a request (on behalf of a browser) might prefer a JSON object over a plain HTML file where as a user browsing with javascript disabled would want the page in HTML. The third argument is a function that converts the abstract object to the desired representation depending on the preferences sent by the client.
The typical values for the first three arguments are,
for the first, yesodRunner
for the second and
yesodDispatch
fmap
.
chooseRep