Copyright | (c) 2015 Athan Clark |
---|---|
License | BSD-style |
Maintainer | athan.clark@gmail.com |
Stability | experimental |
Portability | GHC |
Safe Haskell | None |
Language | Haskell2010 |
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.
- type Tries x s e = (RootedPredTrie Text x, RootedPredTrie Text x, RootedPredTrie Text s, RootedPredTrie Text e)
- newtype HandlerT x sec err aux m a = HandlerT {
- runHandlerT :: StateT (Tries x sec err) m a
- execHandlerT :: Monad m => HandlerT x sec err aux m a -> m (Tries x sec err)
- type ActionT e u m a = VerbListenerT (FileExtListenerT (MiddlewareT m) m a) e u m a
- type RoutableT s e u ue m a = HandlerT (MiddlewareT m) (s, AuthScope) (e -> MiddlewareT m) (e, u, ue) m a
- 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
- data AuthScope
- type ExtrudeSoundly cleanxs xs c r = (cleanxs ~ CatMaybes xs, ArityTypeListIso c cleanxs r, Extrude (UrlChunks xs) (RootedPredTrie Text c) (RootedPredTrie Text r))
- handle :: (Monad m, Functor m, cleanxs ~ CatMaybes xs, HasResult childContent (MiddlewareT m), HasResult childErr (e -> MiddlewareT m), ExpectArity cleanxs childContent, ExpectArity cleanxs childSec, ExpectArity cleanxs childErr, Singleton (UrlChunks xs) childContent (RootedPredTrie Text resultContent), ExtrudeSoundly cleanxs xs childContent resultContent, ExtrudeSoundly cleanxs xs childSec resultSec, ExtrudeSoundly cleanxs xs childErr resultErr) => UrlChunks xs -> Maybe childContent -> Maybe (HandlerT childContent childSec childErr (e, u, ue) m ()) -> HandlerT resultContent resultSec resultErr (e, u, ue) m ()
- handleAction :: (Monad m, Functor m, cleanxs ~ CatMaybes xs, HasResult childContent (ActionT ue u m ()), HasResult childErr (e -> ActionT ue u m ()), ExpectArity cleanxs childContent, ExpectArity cleanxs childSec, ExpectArity cleanxs childErr, Singleton (UrlChunks xs) childContent (RootedPredTrie Text resultContent), ExtrudeSoundly cleanxs xs childContent resultContent, ExtrudeSoundly cleanxs xs childSec resultSec, ExtrudeSoundly cleanxs xs childErr resultErr) => UrlChunks xs -> Maybe childContent -> Maybe (HandlerT childContent childSec childErr (e, u, ue) m ()) -> HandlerT resultContent resultSec resultErr (e, u, ue) m ()
- parent :: (Monad m, Functor m, cleanxs ~ CatMaybes xs, Singleton (UrlChunks xs) childContent (RootedPredTrie Text resultContent), 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 ()
- auth :: (Monad m, Functor m) => sec -> err -> AuthScope -> HandlerT content (sec, AuthScope) err aux m ()
- notFound :: (Monad m, Functor m, cleanxs ~ CatMaybes xs, HasResult childContent (MiddlewareT m), HasResult childErr (e -> MiddlewareT m), ExpectArity cleanxs childContent, ExpectArity cleanxs childSec, ExpectArity cleanxs childErr, Singleton (UrlChunks xs) childContent (RootedPredTrie Text resultContent), ExtrudeSoundly cleanxs xs childContent resultContent, ExtrudeSoundly cleanxs xs childSec resultSec, ExtrudeSoundly cleanxs xs childErr resultErr) => UrlChunks xs -> Maybe childContent -> Maybe (HandlerT childContent childSec childErr (e, u, ue) m ()) -> HandlerT resultContent resultSec resultErr (e, u, ue) m ()
- notFoundAction :: (Monad m, Functor m, cleanxs ~ CatMaybes xs, HasResult childContent (ActionT ue u m ()), HasResult childErr (e -> ActionT ue u m ()), ExpectArity cleanxs childContent, ExpectArity cleanxs childSec, ExpectArity cleanxs childErr, Singleton (UrlChunks xs) childContent (RootedPredTrie Text resultContent), ExtrudeSoundly cleanxs xs childContent resultContent, ExtrudeSoundly cleanxs xs childSec resultSec, ExtrudeSoundly cleanxs xs childErr resultErr) => UrlChunks xs -> Maybe childContent -> Maybe (HandlerT childContent childSec childErr (e, u, ue) m ()) -> HandlerT resultContent resultSec resultErr (e, u, ue) m ()
- action :: MonadIO m => ActionT e u m () -> MiddlewareT m
- route :: (Functor m, Monad m, MonadIO m) => HandlerT (MiddlewareT m) sec err aux m () -> MiddlewareT m
- routeAuth :: (Functor m, Monad m, MonadIO m) => (Request -> [sec] -> ExceptT e m (Response -> Response)) -> RoutableT sec e u ue m () -> MiddlewareT m
- routeAction :: (Functor m, Monad m, MonadIO m) => RoutableActionT sec e u ue m () -> MiddlewareT m
- routeActionAuth :: (Functor m, Monad m, MonadIO m) => (Request -> [sec] -> ExceptT e m (Response -> Response)) -> RoutableActionT sec e u ue m () -> MiddlewareT m
- extractContent :: (Functor m, Monad m, MonadIO m) => HandlerT (MiddlewareT m) sec err aux m a -> MiddlewareT m
- extractNotFound :: (Functor m, Monad m, MonadIO m) => HandlerT (MiddlewareT m) sec err aux m a -> MiddlewareT m
- extractAuthSym :: (Functor m, Monad m) => HandlerT x (sec, AuthScope) err aux m a -> Request -> m [sec]
- extractAuth :: (Functor m, Monad m, MonadIO m) => (Request -> [sec] -> ExceptT e m (Response -> Response)) -> HandlerT x (sec, AuthScope) (e -> MiddlewareT m) aux m a -> MiddlewareT m
- 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
- actionToMiddleware :: MonadIO m => RoutableActionT sec e u ue m () -> RoutableT sec e u ue m ()
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
HandlerT | |
|
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 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
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, cleanxs ~ CatMaybes xs, HasResult childContent (MiddlewareT m), HasResult childErr (e -> MiddlewareT m), ExpectArity cleanxs childContent, ExpectArity cleanxs childSec, ExpectArity cleanxs childErr, Singleton (UrlChunks xs) childContent (RootedPredTrie Text resultContent), ExtrudeSoundly cleanxs xs childContent resultContent, ExtrudeSoundly cleanxs xs childSec resultSec, ExtrudeSoundly cleanxs xs childErr resultErr) => UrlChunks xs -> Maybe childContent -> Maybe (HandlerT childContent childSec childErr (e, u, ue) m ()) -> HandlerT resultContent resultSec resultErr (e, u, ue) m () Source
Embed a MiddlewareT
into a set of routes.
handleAction :: (Monad m, Functor m, cleanxs ~ CatMaybes xs, HasResult childContent (ActionT ue u m ()), HasResult childErr (e -> ActionT ue u m ()), ExpectArity cleanxs childContent, ExpectArity cleanxs childSec, ExpectArity cleanxs childErr, Singleton (UrlChunks xs) childContent (RootedPredTrie Text resultContent), ExtrudeSoundly cleanxs xs childContent resultContent, ExtrudeSoundly cleanxs xs childSec resultSec, ExtrudeSoundly cleanxs xs childErr resultErr) => UrlChunks xs -> Maybe childContent -> Maybe (HandlerT childContent childSec childErr (e, u, ue) m ()) -> HandlerT resultContent resultSec resultErr (e, u, ue) m () Source
Embed an ActionT
into a set of routes directly, without first converting
it to a MiddlewareT
.
parent :: (Monad m, Functor m, cleanxs ~ CatMaybes xs, Singleton (UrlChunks xs) childContent (RootedPredTrie Text resultContent), 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, cleanxs ~ CatMaybes xs, HasResult childContent (MiddlewareT m), HasResult childErr (e -> MiddlewareT m), ExpectArity cleanxs childContent, ExpectArity cleanxs childSec, ExpectArity cleanxs childErr, Singleton (UrlChunks xs) childContent (RootedPredTrie Text resultContent), ExtrudeSoundly cleanxs xs childContent resultContent, ExtrudeSoundly cleanxs xs childSec resultSec, ExtrudeSoundly cleanxs xs childErr resultErr) => UrlChunks xs -> Maybe childContent -> Maybe (HandlerT childContent childSec childErr (e, u, ue) m ()) -> HandlerT resultContent resultSec resultErr (e, u, ue) m () Source
Embed a MiddlewareT
as a not-found handler into a set of routes.
notFoundAction :: (Monad m, Functor m, cleanxs ~ CatMaybes xs, HasResult childContent (ActionT ue u m ()), HasResult childErr (e -> ActionT ue u m ()), ExpectArity cleanxs childContent, ExpectArity cleanxs childSec, ExpectArity cleanxs childErr, Singleton (UrlChunks xs) childContent (RootedPredTrie Text resultContent), ExtrudeSoundly cleanxs xs childContent resultContent, ExtrudeSoundly cleanxs xs childSec resultSec, ExtrudeSoundly cleanxs xs childErr resultErr) => UrlChunks xs -> Maybe childContent -> Maybe (HandlerT childContent childSec childErr (e, u, ue) m ()) -> HandlerT resultContent resultSec resultErr (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
:: (Functor m, Monad m, MonadIO m) | |
=> HandlerT (MiddlewareT m) sec err aux m () | Assembled |
-> MiddlewareT m |
Turns a HandlerT
containing MiddlewareT
s into a MiddlewareT
.
:: (Functor m, Monad m, MonadIO m) | |
=> (Request -> [sec] -> ExceptT e m (Response -> Response)) | authorize |
-> RoutableT sec e u ue m () | Assembled |
-> MiddlewareT m |
Given a security verification function that returns a method to updating the session,
turn a set of routes containing MiddlewareT
s 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 ActionT
s -
essentially fmap
ing action
to each element.
:: (Functor m, Monad m, MonadIO m) | |
=> (Request -> [sec] -> ExceptT e m (Response -> Response)) | authorize |
-> RoutableActionT sec e u ue m () | Assembled |
-> 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] -> ExceptT e m (Response -> Response)) -> 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 ActionT
s into a HandlerT
containing MiddlewareT
s.