yesod-routes-0.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.

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 three arguments. The third (a list of Resources) is self-explanatory. We'll discuss the first two. 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.