yesod-routes-1.0.1: Efficient routing for Yesod.

Safe HaskellNone

Yesod.Routes.TH

Contents

Synopsis

Data types

data Resource typ Source

Instances

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

data Piece typ Source

Constructors

Static String 
Dynamic typ 

Instances

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

data Dispatch typ Source

Constructors

Methods 

Fields

methodsMulti :: Maybe typ

type of the multi piece at the end

methodsMethods :: [String]

supported request methods

Subsite 

Fields

subsiteType :: typ
 
subsiteFunc :: String
 

Instances

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

Helper functions

Functions

RenderRoute

mkRenderRouteInstance :: Type -> [Resource Type] -> Q DecSource

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 -> [Resource Type] -> Q DecSource

A more general version of mkRenderRouteInstance which takes an additional context.

mkRouteCons :: [Resource Type] -> [Con]Source

Generate the constructors of a route data type.

mkRenderRouteClauses :: [Resource Type] -> Q [Clause]Source

Clauses for the renderRoute method.

Dispatch

Dispatch

mkDispatchClauseSource

Arguments

:: Q Exp

runHandler function

-> Q Exp

dispatcher function

-> Q Exp

fixHandler function

-> [Resource 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.