yesod-routes- Efficient routing for Yesod.

Safe HaskellNone




Data types

data Resource typ Source


Functor Resource 
Show typ => Show (Resource typ) 
Lift t => Lift (Resource t) 

data Piece typ Source


Static String 
Dynamic typ 


Functor Piece 
Show typ => Show (Piece typ) 
Lift t => Lift (Piece t) 

data Dispatch typ Source




methodsMulti :: Maybe typ

type of the multi piece at the end

methodsMethods :: [String]

supported request methods



subsiteType :: typ
subsiteFunc :: String


Functor Dispatch 
Show typ => Show (Dispatch typ) 
Lift t => Lift (Dispatch t) 

Helper functions



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.





:: 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 Resources) 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, yesodRunner for the first, yesodDispatch for the second and fmap chooseRep.