nested-routes-8.1.0: Declarative, compositional Wai responses

Copyright(c) 2015 Athan Clark
LicenseBSD-style
Maintainerathan.clark@gmail.com
Stabilityexperimental
PortabilityGHC
Safe HaskellNone
LanguageHaskell2010

Web.Routes.Nested

Contents

Description

This module exports most of what you'll need for sophisticated routing - all the tools from wai-middleware-verbs (routing for the incoming HTTP method) and wai-middleware-content-type (routing for the incoming Accept header, and implied file extension), WAI itself, and wai-transformers - some simple type aliases wrapped around WAI's Application and Middleware types, allowing us to embed monad transformer stacks for our applications.

To match a route, you have a few options - you can match against a string literal, a regular expression (via regex-compat), or an attoparsec parser. This list will most likely grow in the future, depending on demand.

There is also support for embedding security layers in your routes, in the same nested manner. By "tagging" a set of routes with an authorization role (with auth), you populate a list of roles breached during any request. The function argument to routeAuth guards a Request to pass or fail at the high level, while auth lets you create your authorization boundaries on a case-by-case basis. Both allow you to tap into the monad transformer stack for logging, STRefs, database queries, etc.

Synopsis

Router Construction

match Source #

Arguments

:: (Monad m, Match xs' xs (MiddlewareT m) resultContent) 
=> UrlChunks xs

Predicative path to match against

-> MiddlewareT m

The response to send

-> RouterT resultContent sec m () 

Embed a MiddlewareT into a set of routes via a matching string. You should expect the match to create arity in your handler - the childContent variable. The arity of childContent may grow or shrink, depending on the heterogeneous list created from the list of parsers, regular expressions, or arbitrary predicates in the order written - so something like:

match (p_ "double-parser" double </> o_)
  handler

...then handler must have arity Double ->. If this route was at the top level, then the total arity must be Double -> MiddlewareT m.

Generally, if the routes you are building get grouped by a predicate with matchGroup, then we would need another level of arity before the Double.

matchHere Source #

Arguments

:: Monad m 
=> MiddlewareT m

The response to send

-> RouterT (MiddlewareT m) sec m () 

Create a handle for the current route - an alias for h -> match o_ h.

matchAny Source #

Arguments

:: Monad m 
=> MiddlewareT m

The response to send

-> RouterT (MiddlewareT m) sec m () 

Match against any route, as a last resort against all failing matches - use this for a catch-all at some level in their routes, something like a not-found 404 page is useful.

matchGroup Source #

Arguments

:: (Monad m, MatchGroup xs' xs childContent resultContent childSec resultSec) 
=> UrlChunks xs

Predicative path to match against

-> RouterT childContent childSec m ()

Child routes to nest

-> RouterT resultContent resultSec m () 

Prepends a common route to an existing set of routes. You should note that doing this with a parser or regular expression will necessitate the existing arity in the handlers before the progam can compile.

auth Source #

Arguments

:: Monad m 
=> sec

Your security token

-> AuthScope 
-> RouterT content (SecurityToken sec) m () 

Sets the security role and error handler for a set of routes, optionally including its parent route.

Routing Middleware

route Source #

Arguments

:: MonadIO m 
=> RouterT (MiddlewareT m) sec m a

The Router

-> MiddlewareT m 

Use this function to run your RouterT into a MiddlewareT; making your router executable in WAI. Note that this only responds with content, and doesn't protect your routes with your calls to auth; to protect routes, postcompose this with routeAuth:

route routes . routeAuth routes

routeAuth Source #

Arguments

:: (MonadIO m, MonadThrow m) 
=> (Request -> [sec] -> m ())

authorization method

-> RouterT (MiddlewareT m) (SecurityToken sec) m a

The Router

-> MiddlewareT m 

Supply a method to decide whether or not to throwM an exception based on the current Request and the layers of auth tokens passed in your router, turn your router into a guard for middlewares, basically.

Precise Route Extraction

extractMatch Source #

Arguments

:: MonadIO m 
=> [Text]

The path to match against

-> RouterT r sec m a

The Router

-> m (Maybe r) 

Extracts only the normal match, matchGroup and matchHere routes.

extractMatchAny Source #

Arguments

:: MonadIO m 
=> [Text]

The path to match against

-> RouterT r sec m a

The Router

-> m (Maybe r) 

Extracts only the matchAny responses; something like the greatest-lower-bound.

extractAuthSym Source #

Arguments

:: MonadIO m 
=> [Text]

The path to match against

-> RouterT x (SecurityToken sec) m a

The Router

-> m [sec] 

Find the security tokens / authorization roles affiliated with a request for a set of routes.

extractAuth Source #

Arguments

:: (MonadIO m, MonadThrow m) 
=> (Request -> [sec] -> m ())

authorization method

-> Request 
-> RouterT x (SecurityToken sec) m a 
-> m () 

Extracts only the security handling logic, and turns it into a guard.

extractNearestVia Source #

Arguments

:: MonadIO m 
=> [Text]

The path to match against

-> (RouterT r sec m a -> m (RootedPredTrie Text r)) 
-> RouterT r sec m a 
-> m (Maybe r) 

Given a way to draw out a special-purpose trie from our route set, route to the responses based on a furthest-route-reached method, or like a greatest-lower-bound.

Metadata

data SecurityToken s Source #

Use a custom security token type and an AuthScope to define where and what kind of security should take place.

Constructors

SecurityToken 

data AuthScope Source #

Designate the scope of security to the set of routes - either only the adjacent routes, or the adjacent and the parent container node (root node if not declared).

type Match xs' xs childContent resultContent = (xs' ~ CatMaybes xs, Singleton (UrlChunks xs) childContent (RootedPredTrie Text resultContent), ArityTypeListIso childContent xs' resultContent) Source #

The constraints necessary for match.

type MatchGroup xs' xs childContent resultContent childSec resultSec = (ExtrudeSoundly xs' xs childContent resultContent, ExtrudeSoundly xs' xs childSec resultSec) Source #

The constraints necessary for matchGroup.

Re-Exports