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.
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.
- match :: Monad m => Match xs' xs childContent resultContent => UrlChunks xs -> childContent -> RouterT resultContent sec m ()
- matchHere :: Monad m => childContent -> RouterT childContent sec m ()
- matchAny :: Monad m => childContent -> RouterT childContent sec m ()
- matchGroup :: Monad m => MatchGroup xs' xs childContent resultContent childSec resultSec => UrlChunks xs -> RouterT childContent childSec m () -> RouterT resultContent resultSec m ()
- auth :: Monad m => sec -> AuthScope -> RouterT content (SecurityToken sec) m ()
- route :: MonadIO m => RouterT (MiddlewareT m) sec m a -> MiddlewareT m
- routeAuth :: MonadIO m => MonadThrow m => (Request -> [sec] -> m ()) -> RouterT (MiddlewareT m) (SecurityToken sec) m a -> MiddlewareT m
- extractMatch :: MonadIO m => [Text] -> RouterT r sec m a -> m (Maybe r)
- extractMatchAny :: MonadIO m => [Text] -> RouterT r sec m a -> m (Maybe r)
- extractAuthSym :: MonadIO m => [Text] -> RouterT x (SecurityToken sec) m a -> m [sec]
- extractAuth :: MonadIO m => MonadThrow m => (Request -> [sec] -> m ()) -> Request -> RouterT x (SecurityToken sec) m a -> m ()
- extractNearestVia :: MonadIO m => [Text] -> (RouterT r sec m a -> m (RootedPredTrie Text r)) -> RouterT r sec m a -> m (Maybe r)
- data SecurityToken s = SecurityToken {
- securityToken :: !s
- securityScope :: !AuthScope
- data AuthScope
- type Match xs' xs childContent resultContent = (xs' ~ CatMaybes xs, Singleton (UrlChunks xs) childContent (RootedPredTrie Text resultContent), ArityTypeListIso childContent xs' resultContent)
- type MatchGroup xs' xs childContent resultContent childSec resultSec = (ExtrudeSoundly xs' xs childContent resultContent, ExtrudeSoundly xs' xs childSec resultSec)
- module Web.Routes.Nested.Match
- module Web.Routes.Nested.Types
- module Network.Wai.Middleware.Verbs
- module Network.Wai.Middleware.ContentType
Router Construction
:: Monad m | |
=> Match xs' xs childContent resultContent | |
=> UrlChunks xs | Predicative path to match against |
-> childContent | 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
.
Create a handle for the current route - an alias for h -> match o_ h
.
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.
:: 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.
:: 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
:: 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
:: MonadIO m | |
=> MonadThrow m | |
=> (Request -> [sec] -> m ()) | authorization method |
-> RouterT (MiddlewareT m) (SecurityToken sec) m a | The Router |
-> MiddlewareT m |
Precise Route Extraction
Extracts only the normal match
, matchGroup
and matchHere
routes.
Extracts only the matchAny
responses; something like the greatest-lower-bound.
:: 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.
:: 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.
:: 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.
SecurityToken | |
|
Show s => Show (SecurityToken s) 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
module Web.Routes.Nested.Match
module Web.Routes.Nested.Types
module Network.Wai.Middleware.Verbs