nested-routes-6.0.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.

The routing system lets you embed these complicated HTTP verb / content-type sensative responses just as easily as a WAI Middleware. There is enough tooling provided to use one paradigm or the other. Note - nested-routes does not affect the pathInfo of the incoming Request in any way, but merely matches on it and passes control to the designated response.

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. In the authentication parameter in routeAuth and routeActionAuth, the function keeps the session integrity in-place, while auth lets you create your authorization boundaries. Both are symbiotic and neccessary for establishing security, and both allow you to tap into the monad transformer stack to do logging, STM, database queries, etc.

To use your set of routes in a WAI application, you need to "extract" the functionality from your route set - using the route, routeAuth, routeAction, and routeActionAuth functions, you can create monolithic apps very easily. But, if you would like to extract the security middleware to place before say, a static middleware you already have in place, use the extractAuth functions, and others for their respective purposes. This way, you can decompose the routing system into each subject matter, and re-compose (.) them in whichever order you like for your application.

Synopsis

Types

type Tries x s e = (RootedPredTrie Text x, RootedPredTrie Text x, RootedPredTrie Text s, RootedPredTrie Text e) Source

newtype HandlerT x sec err aux m a Source

Constructors

HandlerT 

Fields

runHandlerT :: StateT (Tries x sec err) m a
 

Instances

Monad m => MonadState (Tries x sec err) (HandlerT k x sec err aux m) Source 
MonadTrans (HandlerT k x sec err aux) Source 
Monad m => Monad (HandlerT k x sec err aux m) Source 
Functor m => Functor (HandlerT k x sec err aux m) Source 
Monad m => Applicative (HandlerT k x sec err aux m) Source 
MonadIO m => MonadIO (HandlerT k x sec err aux m) Source 

execHandlerT :: Monad m => HandlerT x sec err aux m a -> m (Tries x sec err) Source

type ActionT e u m a = VerbListenerT (FileExtListenerT (MiddlewareT m) m a) e u m a Source

type RoutableT s e u ue m a = HandlerT (MiddlewareT m) (s, AuthScope) (e -> MiddlewareT m) (e, u, ue) m a Source

type RoutableActionT s e u ue m a = HandlerT (ActionT ue u m ()) (s, AuthScope) (e -> ActionT ue u m ()) (e, u, ue) m a Source

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 ExtrudeSoundly cleanxs xs c r = (cleanxs ~ CatMaybes xs, ArityTypeListIso c cleanxs r, Extrude (UrlChunks xs) (RootedPredTrie Text c) (RootedPredTrie Text r)) Source

Combinators

handle :: (Monad m, Functor m, HasResult childContent (MiddlewareT m), HasResult err (e -> MiddlewareT m), Singleton (UrlChunks xs) childContent (RootedPredTrie Text resultContent), cleanxs ~ CatMaybes xs, ArityTypeListIso childContent cleanxs resultContent) => UrlChunks xs -> childContent -> HandlerT resultContent sec err (e, u, ue) m () Source

Embed a MiddlewareT into a set of routes.

handleAction :: (Monad m, Functor m, HasResult childContent (ActionT ue u m ()), HasResult err (e -> ActionT ue u m ()), Singleton (UrlChunks xs) childContent (RootedPredTrie Text resultContent), cleanxs ~ CatMaybes xs, ArityTypeListIso childContent cleanxs resultContent) => UrlChunks xs -> childContent -> HandlerT resultContent sec err (e, u, ue) m () Source

Embed an ActionT into a set of routes directly, without first converting it to a MiddlewareT.

here :: (Monad m, Functor m, HasResult content (MiddlewareT m), HasResult err (e -> MiddlewareT m)) => content -> HandlerT content sec err (e, u, ue) m () Source

Create a handle for the present route - an alias for h -> handle o (Just h).

hereAction :: (Monad m, Functor m, HasResult content (ActionT ue u m ()), HasResult err (e -> ActionT ue u m ())) => content -> HandlerT content sec err (e, u, ue) m () Source

handleAny :: (Monad m, Functor m, HasResult content (MiddlewareT m), HasResult err (e -> MiddlewareT m)) => content -> HandlerT content sec err (e, u, ue) m () Source

Match against any route, as a last resort against all failing handles.

handleAnyAction :: (Monad m, Functor m, HasResult content (ActionT ue u m ()), HasResult err (e -> ActionT ue u m ())) => content -> HandlerT content sec err (e, u, ue) m () Source

parent :: (Monad m, Functor m, cleanxs ~ CatMaybes xs, ExtrudeSoundly cleanxs xs childContent resultContent, ExtrudeSoundly cleanxs xs childSec resultSec, ExtrudeSoundly cleanxs xs childErr resultErr) => UrlChunks xs -> HandlerT childContent childSec childErr aux m () -> HandlerT resultContent resultSec resultErr aux m () Source

Prepend a path to an existing set of routes.

auth :: (Monad m, Functor m) => sec -> err -> AuthScope -> HandlerT content (sec, AuthScope) err aux m () Source

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

notFound :: (Monad m, Functor m, HasResult content (MiddlewareT m), HasResult err (e -> MiddlewareT m)) => content -> HandlerT content sec err (e, u, ue) m () Source

Embed a MiddlewareT as a not-found handler into a set of routes.

notFoundAction :: (Monad m, Functor m, HasResult content (ActionT ue u m ()), HasResult err (e -> ActionT ue u m ())) => content -> HandlerT content sec err (e, u, ue) m () Source

Embed an ActionT as a not-found handler into a set of routes, without first converting it to a MiddlewareT.

action :: MonadIO m => ActionT e u m () -> MiddlewareT m Source

Turn an ActionT into a MiddlewareT - could be used to make middleware-based route sets cooperate with the content-type and verb combinators.

Routing

route Source

Arguments

:: (Functor m, Monad m, MonadIO m) 
=> HandlerT (MiddlewareT m) sec err aux m ()

Assembled handle calls

-> MiddlewareT m 

Turns a HandlerT containing MiddlewareTs into a MiddlewareT.

routeAuth Source

Arguments

:: (Functor m, Monad m, MonadIO m) 
=> (Request -> [sec] -> m (Response -> Response, Maybe e))

authorize

-> RoutableT sec e u ue m ()

Assembled handle calls

-> MiddlewareT m 

Given a security verification function that returns a method to updating the session, turn a set of routes containing MiddlewareTs into a MiddlewareT, where a session is secured before responding.

routeAction :: (Functor m, Monad m, MonadIO m) => RoutableActionT sec e u ue m () -> MiddlewareT m Source

Exactly like route, except specialized to route sets that contain ActionTs - essentially fmaping action to each element.

routeActionAuth Source

Arguments

:: (Functor m, Monad m, MonadIO m) 
=> (Request -> [sec] -> m (Response -> Response, Maybe e))

authorize

-> RoutableActionT sec e u ue m ()

Assembled handle calls

-> MiddlewareT m 

Exactly like routeAuth, but specialized for ActionT.

Extraction

extractContent :: (Functor m, Monad m, MonadIO m) => HandlerT (MiddlewareT m) sec err aux m a -> MiddlewareT m Source

Extracts only the normal handle (content) routes into a MiddlewareT, disregarding security and not-found responses.

extractNotFound :: (Functor m, Monad m, MonadIO m) => HandlerT (MiddlewareT m) sec err aux m a -> MiddlewareT m Source

Extracts only the notFound responses into a MiddlewareT.

extractAuthSym :: (Functor m, Monad m) => HandlerT x (sec, AuthScope) err aux m a -> Request -> m [sec] Source

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

extractAuth :: (Functor m, Monad m, MonadIO m) => (Request -> [sec] -> m (Response -> Response, Maybe e)) -> HandlerT x (sec, AuthScope) (e -> MiddlewareT m) aux m a -> MiddlewareT m Source

Extracts only the security handling logic into a MiddlewareT.

extractNearestVia :: (Functor m, Monad m, MonadIO m) => (HandlerT (MiddlewareT m) sec err aux m a -> m (RootedPredTrie Text (MiddlewareT m))) -> HandlerT (MiddlewareT m) sec err aux m a -> MiddlewareT m Source

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

actionToMiddleware :: MonadIO m => RoutableActionT sec e u ue m () -> RoutableT sec e u ue m () Source

Turns a HandlerT containing ActionTs into a HandlerT containing MiddlewareTs.