packages feed

wai-routes 0.8.1 → 0.9.0

raw patch · 7 files changed

+420/−147 lines, 7 filesdep +wai-app-staticdep +wai-extradep ~aesonPVP ok

version bump matches the API change (PVP)

Dependencies added: wai-app-static, wai-extra

Dependency ranges changed: aeson

API changes (from Hackage documentation)

- Network.Wai.Middleware.Routes: type Handler master = HandlerS master master
- Network.Wai.Middleware.Routes: type HandlerMM master a = HandlerM master master a
- Network.Wai.Middleware.Routes.Class: class RenderRoute a => ParseRoute a
- Network.Wai.Middleware.Routes.Class: class Eq (Route a) => RenderRoute a where data family Route a
- Network.Wai.Middleware.Routes.Class: class RenderRoute a => RouteAttrs a
- Network.Wai.Middleware.Routes.Class: parseRoute :: ParseRoute a => ([Text], [(Text, Text)]) -> Maybe (Route a)
- Network.Wai.Middleware.Routes.Class: renderRoute :: RenderRoute a => Route a -> ([Text], [(Text, Text)])
- Network.Wai.Middleware.Routes.Class: routeAttrs :: RouteAttrs a => Route a -> Set Text
- Network.Wai.Middleware.Routes.ContentTypes: contentType :: HeaderName
- Network.Wai.Middleware.Routes.ContentTypes: contentTypeFromFile :: FilePath -> ByteString
- Network.Wai.Middleware.Routes.ContentTypes: typeAtom :: ByteString
- Network.Wai.Middleware.Routes.ContentTypes: typeCss :: ByteString
- Network.Wai.Middleware.Routes.ContentTypes: typeFlv :: ByteString
- Network.Wai.Middleware.Routes.ContentTypes: typeGif :: ByteString
- Network.Wai.Middleware.Routes.ContentTypes: typeHtml :: ByteString
- Network.Wai.Middleware.Routes.ContentTypes: typeJavascript :: ByteString
- Network.Wai.Middleware.Routes.ContentTypes: typeJpeg :: ByteString
- Network.Wai.Middleware.Routes.ContentTypes: typeJson :: ByteString
- Network.Wai.Middleware.Routes.ContentTypes: typeOctet :: ByteString
- Network.Wai.Middleware.Routes.ContentTypes: typeOgv :: ByteString
- Network.Wai.Middleware.Routes.ContentTypes: typePlain :: ByteString
- Network.Wai.Middleware.Routes.ContentTypes: typePng :: ByteString
- Network.Wai.Middleware.Routes.ContentTypes: typeRss :: ByteString
- Network.Wai.Middleware.Routes.ContentTypes: typeSvg :: ByteString
- Network.Wai.Middleware.Routes.ContentTypes: typeXml :: ByteString
- Network.Wai.Middleware.Routes.Handler: asContent :: ByteString -> Text -> HandlerM sub master ()
- Network.Wai.Middleware.Routes.Handler: css :: Text -> HandlerM sub master ()
- Network.Wai.Middleware.Routes.Handler: file :: FilePath -> HandlerM sub master ()
- Network.Wai.Middleware.Routes.Handler: filepart :: FilePath -> FilePart -> HandlerM sub master ()
- Network.Wai.Middleware.Routes.Handler: getCookie :: ByteString -> HandlerM sub master (Maybe ByteString)
- Network.Wai.Middleware.Routes.Handler: getCookies :: HandlerM sub master Cookies
- Network.Wai.Middleware.Routes.Handler: header :: HeaderName -> ByteString -> HandlerM sub master ()
- Network.Wai.Middleware.Routes.Handler: html :: Text -> HandlerM sub master ()
- Network.Wai.Middleware.Routes.Handler: instance Control.Monad.IO.Class.MonadIO m => Control.Monad.IO.Class.MonadIO (Network.Wai.Middleware.Routes.Handler.HandlerMI sub master m)
- Network.Wai.Middleware.Routes.Handler: instance Control.Monad.Trans.Class.MonadTrans (Network.Wai.Middleware.Routes.Handler.HandlerMI sub master)
- Network.Wai.Middleware.Routes.Handler: instance GHC.Base.Functor m => GHC.Base.Functor (Network.Wai.Middleware.Routes.Handler.HandlerMI sub master m)
- Network.Wai.Middleware.Routes.Handler: instance GHC.Base.Monad m => Control.Monad.State.Class.MonadState (Network.Wai.Middleware.Routes.Handler.HandlerState sub master) (Network.Wai.Middleware.Routes.Handler.HandlerMI sub master m)
- Network.Wai.Middleware.Routes.Handler: instance GHC.Base.Monad m => GHC.Base.Applicative (Network.Wai.Middleware.Routes.Handler.HandlerMI sub master m)
- Network.Wai.Middleware.Routes.Handler: instance GHC.Base.Monad m => GHC.Base.Monad (Network.Wai.Middleware.Routes.Handler.HandlerMI sub master m)
- Network.Wai.Middleware.Routes.Handler: javascript :: Text -> HandlerM sub master ()
- Network.Wai.Middleware.Routes.Handler: json :: ToJSON a => a -> HandlerM sub master ()
- Network.Wai.Middleware.Routes.Handler: jsonBody :: FromJSON a => HandlerM master master (Either String a)
- Network.Wai.Middleware.Routes.Handler: master :: HandlerM sub master master
- Network.Wai.Middleware.Routes.Handler: maybeRootRoute :: HandlerM sub master (Maybe (Route master))
- Network.Wai.Middleware.Routes.Handler: maybeRoute :: HandlerM sub master (Maybe (Route sub))
- Network.Wai.Middleware.Routes.Handler: next :: HandlerM sub master ()
- Network.Wai.Middleware.Routes.Handler: plain :: Text -> HandlerM sub master ()
- Network.Wai.Middleware.Routes.Handler: raw :: ByteString -> HandlerM sub master ()
- Network.Wai.Middleware.Routes.Handler: rawBody :: HandlerM master master ByteString
- Network.Wai.Middleware.Routes.Handler: readRouteMaster :: ParseRoute master => HandlerM sub master (Text -> Maybe (Route master))
- Network.Wai.Middleware.Routes.Handler: readRouteSub :: ParseRoute sub => HandlerM sub master (Text -> Maybe (Route master))
- Network.Wai.Middleware.Routes.Handler: reqHeader :: ByteString -> HandlerM sub master (Maybe ByteString)
- Network.Wai.Middleware.Routes.Handler: reqHeaders :: HandlerM sub master RequestHeaders
- Network.Wai.Middleware.Routes.Handler: request :: HandlerM sub master Request
- Network.Wai.Middleware.Routes.Handler: rootRouteAttrSet :: RouteAttrs master => HandlerM sub master (Set Text)
- Network.Wai.Middleware.Routes.Handler: routeAttrSet :: RouteAttrs sub => HandlerM sub master (Set Text)
- Network.Wai.Middleware.Routes.Handler: runHandlerM :: HandlerM sub master () -> HandlerS sub master
- Network.Wai.Middleware.Routes.Handler: setCookie :: SetCookie -> HandlerM sub master ()
- Network.Wai.Middleware.Routes.Handler: showRouteMaster :: RenderRoute master => HandlerM sub master (Route master -> Text)
- Network.Wai.Middleware.Routes.Handler: showRouteQueryMaster :: RenderRoute master => HandlerM sub master (Route master -> [(Text, Text)] -> Text)
- Network.Wai.Middleware.Routes.Handler: showRouteQuerySub :: RenderRoute master => HandlerM sub master (Route sub -> [(Text, Text)] -> Text)
- Network.Wai.Middleware.Routes.Handler: showRouteSub :: RenderRoute master => HandlerM sub master (Route sub -> Text)
- Network.Wai.Middleware.Routes.Handler: status :: Status -> HandlerM sub master ()
- Network.Wai.Middleware.Routes.Handler: stream :: StreamingBody -> HandlerM sub master ()
- Network.Wai.Middleware.Routes.Handler: sub :: HandlerM sub master sub
- Network.Wai.Middleware.Routes.Handler: type HandlerM sub master a = HandlerMI sub master IO a
- Network.Wai.Middleware.Routes.Handler: type HandlerMM master a = HandlerM master master a
- Network.Wai.Middleware.Routes.Monad: catchall :: Application -> RouteM ()
- Network.Wai.Middleware.Routes.Monad: defaultAction :: Application -> RouteM ()
- Network.Wai.Middleware.Routes.Monad: instance GHC.Base.Functor Network.Wai.Middleware.Routes.Monad.RouterF
- Network.Wai.Middleware.Routes.Monad: middleware :: Middleware -> RouteM ()
- Network.Wai.Middleware.Routes.Monad: route :: (Routable master master) => master -> RouteM ()
- Network.Wai.Middleware.Routes.Monad: toWaiApp :: Monad m => RouteM () -> m Application
- Network.Wai.Middleware.Routes.Monad: type RouteM = F RouterF
- Network.Wai.Middleware.Routes.Monad: waiApp :: RouteM () -> Application
- Network.Wai.Middleware.Routes.Overlap: Overlap :: ([String] -> [String]) -> ResourceTree t -> ResourceTree t -> Overlap t
- Network.Wai.Middleware.Routes.Overlap: [overlap1] :: Overlap t -> ResourceTree t
- Network.Wai.Middleware.Routes.Overlap: [overlap2] :: Overlap t -> ResourceTree t
- Network.Wai.Middleware.Routes.Overlap: [overlapParents] :: Overlap t -> [String] -> [String]
- Network.Wai.Middleware.Routes.Overlap: data Overlap t
- Network.Wai.Middleware.Routes.Overlap: findOverlapNames :: [ResourceTree t] -> [(String, String)]
- Network.Wai.Middleware.Routes.Parse: TTApp :: TypeTree -> TypeTree -> TypeTree
- Network.Wai.Middleware.Routes.Parse: TTList :: TypeTree -> TypeTree
- Network.Wai.Middleware.Routes.Parse: TTTerm :: String -> TypeTree
- Network.Wai.Middleware.Routes.Parse: data TypeTree
- Network.Wai.Middleware.Routes.Parse: instance GHC.Classes.Eq Network.Wai.Middleware.Routes.Parse.TypeTree
- Network.Wai.Middleware.Routes.Parse: instance GHC.Show.Show Network.Wai.Middleware.Routes.Parse.TypeTree
- Network.Wai.Middleware.Routes.Parse: parseRoutes :: QuasiQuoter
- Network.Wai.Middleware.Routes.Parse: parseRoutesFile :: FilePath -> Q Exp
- Network.Wai.Middleware.Routes.Parse: parseRoutesFileNoCheck :: FilePath -> Q Exp
- Network.Wai.Middleware.Routes.Parse: parseRoutesNoCheck :: QuasiQuoter
- Network.Wai.Middleware.Routes.Parse: parseType :: String -> Type
- Network.Wai.Middleware.Routes.Parse: parseTypeTree :: String -> Maybe TypeTree
- Network.Wai.Middleware.Routes.Routes: Env :: master -> sub -> (Route sub -> Route master) -> Env sub master
- Network.Wai.Middleware.Routes.Routes: [envMaster] :: Env sub master -> master
- Network.Wai.Middleware.Routes.Routes: [envSub] :: Env sub master -> sub
- Network.Wai.Middleware.Routes.Routes: [envToMaster] :: Env sub master -> Route sub -> Route master
- Network.Wai.Middleware.Routes.Routes: class RenderRoute a => ParseRoute a
- Network.Wai.Middleware.Routes.Routes: class Eq (Route a) => RenderRoute a where data family Route a
- Network.Wai.Middleware.Routes.Routes: class Routable sub master
- Network.Wai.Middleware.Routes.Routes: class RenderRoute a => RouteAttrs a
- Network.Wai.Middleware.Routes.Routes: currentRoute :: RequestData master -> Maybe (Route master)
- Network.Wai.Middleware.Routes.Routes: data Env sub master
- Network.Wai.Middleware.Routes.Routes: data RequestData master
- Network.Wai.Middleware.Routes.Routes: dispatcher :: Routable sub master => HandlerS sub master
- Network.Wai.Middleware.Routes.Routes: mkRoute :: String -> [ResourceTree String] -> Q [Dec]
- Network.Wai.Middleware.Routes.Routes: mkRouteData :: String -> [ResourceTree String] -> Q [Dec]
- Network.Wai.Middleware.Routes.Routes: mkRouteDispatch :: String -> [ResourceTree String] -> Q [Dec]
- Network.Wai.Middleware.Routes.Routes: mkRouteSubDispatch :: [ResourceTree a] -> Q Exp
- Network.Wai.Middleware.Routes.Routes: nextApp :: RequestData master -> Application
- Network.Wai.Middleware.Routes.Routes: parseRoute :: ParseRoute a => ([Text], [(Text, Text)]) -> Maybe (Route a)
- Network.Wai.Middleware.Routes.Routes: parseRoutes :: QuasiQuoter
- Network.Wai.Middleware.Routes.Routes: parseRoutesFile :: FilePath -> Q Exp
- Network.Wai.Middleware.Routes.Routes: parseRoutesFileNoCheck :: FilePath -> Q Exp
- Network.Wai.Middleware.Routes.Routes: parseRoutesNoCheck :: QuasiQuoter
- Network.Wai.Middleware.Routes.Routes: readRoute :: ParseRoute master => Text -> Maybe (Route master)
- Network.Wai.Middleware.Routes.Routes: renderRoute :: RenderRoute a => Route a -> ([Text], [(Text, Text)])
- Network.Wai.Middleware.Routes.Routes: routeAttrs :: RouteAttrs a => Route a -> Set Text
- Network.Wai.Middleware.Routes.Routes: routeDispatch :: Routable master master => master -> Middleware
- Network.Wai.Middleware.Routes.Routes: runNext :: App master
- Network.Wai.Middleware.Routes.Routes: showRoute :: RenderRoute master => Route master -> Text
- Network.Wai.Middleware.Routes.Routes: showRouteQuery :: RenderRoute master => Route master -> [(Text, Text)] -> Text
- Network.Wai.Middleware.Routes.Routes: type Handler master = HandlerS master master
- Network.Wai.Middleware.Routes.Routes: type HandlerS sub master = Env sub master -> App sub
- Network.Wai.Middleware.Routes.Routes: type ResponseHandler = (Response -> IO ResponseReceived) -> IO ResponseReceived
- Network.Wai.Middleware.Routes.Routes: waiReq :: RequestData master -> Request
- Network.Wai.Middleware.Routes.TH.Dispatch: MkDispatchSettings :: Q Exp -> Q Exp -> Q Exp -> Q Exp -> Q Exp -> Q Exp -> Q Exp -> (Maybe String -> String -> Q Exp) -> MkDispatchSettings
- Network.Wai.Middleware.Routes.TH.Dispatch: [mds404] :: MkDispatchSettings -> Q Exp
- Network.Wai.Middleware.Routes.TH.Dispatch: [mds405] :: MkDispatchSettings -> Q Exp
- Network.Wai.Middleware.Routes.TH.Dispatch: [mdsGetHandler] :: MkDispatchSettings -> Maybe String -> String -> Q Exp
- Network.Wai.Middleware.Routes.TH.Dispatch: [mdsGetPathInfo] :: MkDispatchSettings -> Q Exp
- Network.Wai.Middleware.Routes.TH.Dispatch: [mdsMethod] :: MkDispatchSettings -> Q Exp
- Network.Wai.Middleware.Routes.TH.Dispatch: [mdsRunHandler] :: MkDispatchSettings -> Q Exp
- Network.Wai.Middleware.Routes.TH.Dispatch: [mdsSetPathInfo] :: MkDispatchSettings -> Q Exp
- Network.Wai.Middleware.Routes.TH.Dispatch: [mdsSubDispatcher] :: MkDispatchSettings -> Q Exp
- Network.Wai.Middleware.Routes.TH.Dispatch: data MkDispatchSettings
- Network.Wai.Middleware.Routes.TH.Dispatch: defaultGetHandler :: Maybe String -> String -> Q Exp
- Network.Wai.Middleware.Routes.TH.Dispatch: mkDispatchClause :: MkDispatchSettings -> [ResourceTree a] -> Q Clause
- Network.Wai.Middleware.Routes.TH.ParseRoute: mkParseRouteInstance :: Type -> [ResourceTree a] -> Q Dec
- Network.Wai.Middleware.Routes.TH.RenderRoute: mkRenderRouteClauses :: [ResourceTree Type] -> Q [Clause]
- Network.Wai.Middleware.Routes.TH.RenderRoute: mkRenderRouteInstance :: Type -> [ResourceTree Type] -> Q [Dec]
- Network.Wai.Middleware.Routes.TH.RenderRoute: mkRenderRouteInstance' :: Cxt -> Type -> [ResourceTree Type] -> Q [Dec]
- Network.Wai.Middleware.Routes.TH.RenderRoute: mkRouteCons :: [ResourceTree Type] -> ([Con], [Dec])
- Network.Wai.Middleware.Routes.TH.RouteAttrs: mkRouteAttrsInstance :: Type -> [ResourceTree a] -> Q Dec
- Network.Wai.Middleware.Routes.TH.Types: Dynamic :: typ -> Piece typ
- Network.Wai.Middleware.Routes.TH.Types: FlatResource :: [(String, [Piece a])] -> String -> [Piece a] -> Dispatch a -> Bool -> FlatResource a
- Network.Wai.Middleware.Routes.TH.Types: Methods :: Maybe typ -> [String] -> Dispatch typ
- Network.Wai.Middleware.Routes.TH.Types: Resource :: String -> [Piece typ] -> Dispatch typ -> [String] -> CheckOverlap -> Resource typ
- Network.Wai.Middleware.Routes.TH.Types: ResourceLeaf :: (Resource typ) -> ResourceTree typ
- Network.Wai.Middleware.Routes.TH.Types: ResourceParent :: String -> CheckOverlap -> [Piece typ] -> [ResourceTree typ] -> ResourceTree typ
- Network.Wai.Middleware.Routes.TH.Types: Static :: String -> Piece typ
- Network.Wai.Middleware.Routes.TH.Types: Subsite :: typ -> String -> Dispatch typ
- Network.Wai.Middleware.Routes.TH.Types: [frCheck] :: FlatResource a -> Bool
- Network.Wai.Middleware.Routes.TH.Types: [frDispatch] :: FlatResource a -> Dispatch a
- Network.Wai.Middleware.Routes.TH.Types: [frName] :: FlatResource a -> String
- Network.Wai.Middleware.Routes.TH.Types: [frParentPieces] :: FlatResource a -> [(String, [Piece a])]
- Network.Wai.Middleware.Routes.TH.Types: [frPieces] :: FlatResource a -> [Piece a]
- Network.Wai.Middleware.Routes.TH.Types: [methodsMethods] :: Dispatch typ -> [String]
- Network.Wai.Middleware.Routes.TH.Types: [methodsMulti] :: Dispatch typ -> Maybe typ
- Network.Wai.Middleware.Routes.TH.Types: [resourceAttrs] :: Resource typ -> [String]
- Network.Wai.Middleware.Routes.TH.Types: [resourceCheck] :: Resource typ -> CheckOverlap
- Network.Wai.Middleware.Routes.TH.Types: [resourceDispatch] :: Resource typ -> Dispatch typ
- Network.Wai.Middleware.Routes.TH.Types: [resourceName] :: Resource typ -> String
- Network.Wai.Middleware.Routes.TH.Types: [resourcePieces] :: Resource typ -> [Piece typ]
- Network.Wai.Middleware.Routes.TH.Types: [subsiteFunc] :: Dispatch typ -> String
- Network.Wai.Middleware.Routes.TH.Types: [subsiteType] :: Dispatch typ -> typ
- Network.Wai.Middleware.Routes.TH.Types: data Dispatch typ
- Network.Wai.Middleware.Routes.TH.Types: data FlatResource a
- Network.Wai.Middleware.Routes.TH.Types: data Piece typ
- Network.Wai.Middleware.Routes.TH.Types: data Resource typ
- Network.Wai.Middleware.Routes.TH.Types: data ResourceTree typ
- Network.Wai.Middleware.Routes.TH.Types: flatten :: [ResourceTree a] -> [FlatResource a]
- Network.Wai.Middleware.Routes.TH.Types: instance GHC.Base.Functor Network.Wai.Middleware.Routes.TH.Types.Dispatch
- Network.Wai.Middleware.Routes.TH.Types: instance GHC.Base.Functor Network.Wai.Middleware.Routes.TH.Types.Piece
- Network.Wai.Middleware.Routes.TH.Types: instance GHC.Base.Functor Network.Wai.Middleware.Routes.TH.Types.Resource
- Network.Wai.Middleware.Routes.TH.Types: instance GHC.Base.Functor Network.Wai.Middleware.Routes.TH.Types.ResourceTree
- Network.Wai.Middleware.Routes.TH.Types: instance GHC.Show.Show typ => GHC.Show.Show (Network.Wai.Middleware.Routes.TH.Types.Dispatch typ)
- Network.Wai.Middleware.Routes.TH.Types: instance GHC.Show.Show typ => GHC.Show.Show (Network.Wai.Middleware.Routes.TH.Types.Piece typ)
- Network.Wai.Middleware.Routes.TH.Types: instance GHC.Show.Show typ => GHC.Show.Show (Network.Wai.Middleware.Routes.TH.Types.Resource typ)
- Network.Wai.Middleware.Routes.TH.Types: instance Language.Haskell.TH.Syntax.Lift t => Language.Haskell.TH.Syntax.Lift (Network.Wai.Middleware.Routes.TH.Types.Dispatch t)
- Network.Wai.Middleware.Routes.TH.Types: instance Language.Haskell.TH.Syntax.Lift t => Language.Haskell.TH.Syntax.Lift (Network.Wai.Middleware.Routes.TH.Types.Piece t)
- Network.Wai.Middleware.Routes.TH.Types: instance Language.Haskell.TH.Syntax.Lift t => Language.Haskell.TH.Syntax.Lift (Network.Wai.Middleware.Routes.TH.Types.Resource t)
- Network.Wai.Middleware.Routes.TH.Types: instance Language.Haskell.TH.Syntax.Lift t => Language.Haskell.TH.Syntax.Lift (Network.Wai.Middleware.Routes.TH.Types.ResourceTree t)
- Network.Wai.Middleware.Routes.TH.Types: resourceMulti :: Resource typ -> Maybe typ
- Network.Wai.Middleware.Routes.TH.Types: resourceTreeName :: ResourceTree typ -> String
- Network.Wai.Middleware.Routes.TH.Types: resourceTreePieces :: ResourceTree typ -> [Piece typ]
- Network.Wai.Middleware.Routes.TH.Types: type CheckOverlap = Bool
- Util.Free: F :: (forall r. (a -> r) -> (f r -> r) -> r) -> F f a
- Util.Free: [runF] :: F f a -> forall r. (a -> r) -> (f r -> r) -> r
- Util.Free: instance GHC.Base.Functor f => GHC.Base.Applicative (Util.Free.F f)
- Util.Free: instance GHC.Base.Functor f => GHC.Base.Functor (Util.Free.F f)
- Util.Free: instance GHC.Base.Functor f => GHC.Base.Monad (Util.Free.F f)
- Util.Free: liftF :: Functor f => f a -> F f a
- Util.Free: newtype F f a
+ Network.Wai.Middleware.Routes: DefaultMaster :: DefaultMaster
+ Network.Wai.Middleware.Routes: data DefaultMaster
+ Network.Wai.Middleware.Routes: data Text :: *
+ Network.Wai.Middleware.Routes: getFileParam :: Text -> HandlerM sub master (Maybe FileInfo)
+ Network.Wai.Middleware.Routes: getFileParams :: HandlerM sub master [(Text, FileInfo)]
+ Network.Wai.Middleware.Routes: getParam :: Text -> HandlerM sub master (Maybe Text)
+ Network.Wai.Middleware.Routes: getParams :: HandlerM sub master [(Text, Text)]
+ Network.Wai.Middleware.Routes: getPostParam :: Text -> HandlerM sub master (Maybe Text)
+ Network.Wai.Middleware.Routes: getPostParams :: HandlerM sub master [(Text, Text)]
+ Network.Wai.Middleware.Routes: getQueryParam :: Text -> HandlerM sub master (Maybe Text)
+ Network.Wai.Middleware.Routes: getQueryParams :: HandlerM sub master [(Text, Text)]
+ Network.Wai.Middleware.Routes: handler :: Handler DefaultMaster -> RouteM ()
+ Network.Wai.Middleware.Routes: isWebsocket :: HandlerM sub master Bool
+ Network.Wai.Middleware.Routes: rawBuilder :: Builder -> HandlerM sub master ()
- Network.Wai.Middleware.Routes: getCookie :: ByteString -> HandlerM sub master (Maybe ByteString)
+ Network.Wai.Middleware.Routes: getCookie :: Text -> HandlerM sub master (Maybe Text)
- Network.Wai.Middleware.Routes: getCookies :: HandlerM sub master Cookies
+ Network.Wai.Middleware.Routes: getCookies :: HandlerM sub master CookiesText
- Network.Wai.Middleware.Routes: jsonBody :: FromJSON a => HandlerM master master (Either String a)
+ Network.Wai.Middleware.Routes: jsonBody :: FromJSON a => HandlerM sub master (Either String a)
- Network.Wai.Middleware.Routes: rawBody :: HandlerM master master ByteString
+ Network.Wai.Middleware.Routes: rawBody :: HandlerM sub master ByteString
- Network.Wai.Middleware.Routes: reqHeader :: ByteString -> HandlerM sub master (Maybe ByteString)
+ Network.Wai.Middleware.Routes: reqHeader :: Text -> HandlerM sub master (Maybe Text)
- Network.Wai.Middleware.Routes: route :: (Routable master master) => master -> RouteM ()
+ Network.Wai.Middleware.Routes: route :: Routable master master => master -> RouteM ()

Files

README.md view
@@ -1,4 +1,4 @@-[Wai-Routes](https://ajnsit.github.io/wai-routes) [![Hackage](https://img.shields.io/badge/hackage-v0.8.1-brightgreen.svg)](https://hackage.haskell.org/package/wai-routes) [![Hackage-Deps](https://img.shields.io/hackage-deps/v/wai-routes.svg)](http://packdeps.haskellers.com/feed?needle=wai-routes) [![Build Status](https://img.shields.io/travis/ajnsit/wai-routes.svg)](https://travis-ci.org/ajnsit/wai-routes) [![Coverage Status](https://coveralls.io/repos/ajnsit/wai-routes/badge.svg?branch=master&service=github)](https://coveralls.io/github/ajnsit/wai-routes?branch=master)+[Wai-Routes](https://ajnsit.github.io/wai-routes) [![Hackage](https://img.shields.io/badge/hackage-v0.9.0-brightgreen.svg)](https://hackage.haskell.org/package/wai-routes) [![Hackage-Deps](https://img.shields.io/hackage-deps/v/wai-routes.svg)](http://packdeps.haskellers.com/feed?needle=wai-routes) [![Build Status](https://img.shields.io/travis/ajnsit/wai-routes.svg)](https://travis-ci.org/ajnsit/wai-routes) [![Coverage Status](https://coveralls.io/repos/ajnsit/wai-routes/badge.svg?branch=master&service=github)](https://coveralls.io/github/ajnsit/wai-routes?branch=master) ====================================  Wai-routes is a micro web framework for Haskell that focuses on typesafe URLs.@@ -16,6 +16,7 @@     - Nested Routes     - Subsites     - Route Annotations+  - Seamlessly mix and match "unrouted" request handlers with typesafe routing.   - Sitewide Master data which is passed to all handlers and can be used for persistent data (like DB connections)   - Easy to use Handler Monad which allows direct access to request and master data   - Easy composition of multiple routes and middleware to construct an application@@ -62,7 +63,32 @@  Wai has had the ability to stream content for a long time. Now wai-routes exposes this functionality with the `stream` function. This example shows how to stream content in a handler. Note that most browsers using default settings will not show content as it is being streamed. You can use "curl" to observe the effect of streaming. E.g. - `curl localhost:8080` will dump the data as it is being streamed from the server. +**Example 7. Kitchen sink ** - [Code](examples/kitchen) +*Work in progress*. Demonstrates all major features in wai-routes.+++Deployment+==========++The current recommended route (pun not intended) for deploying wai-routes apps is [keter](http://hackage.haskell.org/package/keter). You need to read the port from the environment variables -++    -- Run the application+    main :: IO ()+    main = do+      port' <- getEnv "PORT"+      let port = read port'+      run port $ waiApp application++Then put something like this in `config/keter.yaml` -++    exec: ../path/to/executable+    host: mydomainname.example.com++Then create a tarball with `config/keter.yaml`, `path/to/executable`, and any other files needed at runtime for your application. Rename the tarball to have a `.keter` extension.++Upload that file to your server's `incoming` folder for keter to pick it up. You obviously need keter already installed and configured properly at the server.+ Planned Features ==================== @@ -71,15 +97,15 @@ - Support for raw network responses (see http://hackage.haskell.org/package/wai-3.0.3.0/docs/Network-Wai.html#v:responseRaw) - Seamless websocket support - Development mode-- Keter and Heroku support - Scaffolding-- Better documentation-- Tests and code coverage+- Better documentation, and a getting started tutorial+- More tests and code coverage   Changelog ========= +* 0.9.0 : Support for "unrouted" handlers. API changes to avoid returning lazy text or bytestring. Methods to fetch post/file params. Removed 'HandlerMM' and made 'Handler' more useful. * 0.8.1 : Bumped dependencies. Added 'HandlerMM' type alias * 0.8.0 : Replaced 'show/renderRoute' with 'show/renderRouteSub' and 'show/renderRouteMaster'. Added functions to access request headers (reqHeader/s), send a part of a file (filepart). Auto infer mime-types when sending files. Added cookie handling functions (get/setCookie/s). Added 'sub' to allow access to subsite datatype. * 0.7.3 : Added 'stream' to stream responses. Added 'asContent', 'css', and 'javascript' functions.
src/Network/Wai/Middleware/Routes.hs view
@@ -51,6 +51,9 @@      -- * Route Monad makes it easy to compose routes together     , RouteM+    , DefaultMaster(..)+    , Route(DefaultRoute)+    , handler                -- | Add a wai-routes handler     , catchall               -- | Catch all routes with the supplied application     , defaultAction          -- | A synonym for `catchall`, kept for backwards compatibility     , middleware             -- | Add another middleware to the app@@ -60,9 +63,9 @@      -- * HandlerM Monad makes it easy to build a handler     , HandlerM()-    , HandlerMM()            -- | HandlerM Monad specialised for top level sites (no subsites)     , runHandlerM            -- | Run a HandlerM to get a Handler     , request                -- | Access the request data+    , isWebsocket            -- | Is this a websocket request     , reqHeader              -- | Get a particular request header (case insensitive)     , reqHeaders             -- | Get all request headers (case insensitive)     , maybeRootRoute         -- | Access the current route for root route@@ -79,6 +82,7 @@     , filepart               -- | Send a part of a file as response     , stream                 -- | Stream a response     , raw                    -- | Set the raw response body+    , rawBuilder             -- | Set the raw response body as a ByteString Builder     , json                   -- | Set the json response body     , plain                  -- | Set the plain text response body     , html                   -- | Set the html response body@@ -86,13 +90,29 @@     , javascript             -- | Set the javascript response body     , asContent              -- | Set the contentType and a 'Text' body     , next                   -- | Run the next application in the stack+    , getParams              -- | Get all params (query or post, not file)+    , getParam               -- | Get a particular param (query or post, not file)+    , getQueryParams         -- | Get all query params+    , getQueryParam          -- | Get a particular query param+    , getPostParams          -- | Get all post params+    , getPostParam           -- | Get a particular post param+    , getFileParams          -- | Get all file params+    , getFileParam           -- | Get a particular file param     , setCookie              -- | Add a cookie to the response     , getCookie              -- | Get a cookie from the request     , getCookies             -- | Get all cookies from the request++    , module Network.HTTP.Types.Status+    , module Network.Wai.Middleware.RequestLogger+    , module Network.Wai.Application.Static+    , Text   )   where  import Network.Wai.Middleware.Routes.Routes import Network.Wai.Middleware.Routes.Monad import Network.Wai.Middleware.Routes.Handler-+import Network.HTTP.Types.Status+import Network.Wai.Middleware.RequestLogger+import Network.Wai.Application.Static+import Data.Text (Text)
+ src/Network/Wai/Middleware/Routes/DefaultRoute.hs view
@@ -0,0 +1,35 @@+{-# LANGUAGE TypeFamilies #-}++{- |+Module      :  Network.Wai.Middleware.Routes.DefaultRoute+Copyright   :  (c) Anupam Jain 2013 - 2015+License     :  MIT (see the file LICENSE)++Maintainer  :  ajnsit@gmail.com+Stability   :  experimental+Portability :  non-portable (uses ghc extensions)++Defines a DefaultMaster datatype and associated route (DefaultRoute) which is used for "unrouted" handlers+-}+module Network.Wai.Middleware.Routes.DefaultRoute+  ( DefaultMaster(..)+  , Route(DefaultRoute)+  )+  where++import Data.Text (Text)+import Data.Set (empty)++import Network.Wai.Middleware.Routes.Routes++-- Default master datatype, which is used for "unrouted" handlers+data DefaultMaster = DefaultMaster+-- This makes it possible to define handlers without routing stuff+instance RenderRoute DefaultMaster where+  -- The associated route simply contains all path information+  data Route DefaultMaster = DefaultRoute ([Text],[(Text, Text)]) deriving Eq+  renderRoute (DefaultRoute r) = r+instance ParseRoute DefaultMaster where+  parseRoute = Just . DefaultRoute+instance RouteAttrs DefaultMaster where+  routeAttrs = const empty
src/Network/Wai/Middleware/Routes/Handler.hs view
@@ -12,9 +12,9 @@ -} module Network.Wai.Middleware.Routes.Handler     ( HandlerM()             -- | A Monad that makes it easier to build a Handler-    , HandlerMM()            -- | HandlerM Monad specialised for top level sites (no subsites)     , runHandlerM            -- | Run a HandlerM to get a Handler     , request                -- | Access the request data+    , isWebsocket            -- | Is this a websocket request     , reqHeader              -- | Get a particular request header (case insensitive)     , reqHeaders             -- | Get all request headers (case insensitive)     , routeAttrSet           -- | Access the route attribute list@@ -29,7 +29,7 @@     , readRouteSub           -- | Get the route parsing function for the subsite     , master                 -- | Access the master datatype     , sub                    -- | Access the sub datatype-    , rawBody                -- | Consume and return the request body as a lazy bytestring+    , rawBody                -- | Consume and return the request body as a bytestring     , jsonBody               -- | Consume and return the request body as JSON     , header                 -- | Add a header to the response     , status                 -- | Set the response status@@ -37,6 +37,7 @@     , filepart               -- | Send a part of a file as response     , stream                 -- | Stream a response     , raw                    -- | Set the raw response body+    , rawBuilder             -- | Set the raw response body as a ByteString Builder     , json                   -- | Set the json response body     , plain                  -- | Set the plain text response body     , html                   -- | Set the html response body@@ -44,17 +45,25 @@     , javascript             -- | Set the javascript response body     , asContent              -- | Set the contentType and a 'Text' body     , next                   -- | Run the next application in the stack+    , getParams              -- | Get all params (query or post, not file)+    , getParam               -- | Get a particular param (query or post, not file)+    , getQueryParams         -- | Get all query params+    , getQueryParam          -- | Get a particular query param+    , getPostParams          -- | Get all post params+    , getPostParam           -- | Get a particular post param+    , getFileParams          -- | Get all file params+    , getFileParam           -- | Get a particular file param     , setCookie              -- | Add a cookie to the response     , getCookie              -- | Get a cookie from the request     , getCookies             -- | Get all cookies from the request     )     where -import Network.Wai (Request, Response, responseFile, responseBuilder, responseStream, pathInfo, queryString, requestBody, StreamingBody, requestHeaders, FilePart)+import Network.Wai (Request, Response, responseRaw, responseFile, responseBuilder, responseStream, pathInfo, queryString, requestBody, StreamingBody, requestHeaders, FilePart) #if MIN_VERSION_wai(3,0,1) import Network.Wai (strictRequestBody) #endif-import Network.Wai.Middleware.Routes.Routes (Env(..), RequestData, HandlerS, waiReq, currentRoute, runNext, ResponseHandler, showRoute, showRouteQuery, readRoute)+import Network.Wai.Middleware.Routes.Routes (Env(..), RequestData, HandlerS, waiReq, currentRoute, runNext, ResponseHandler, showRoute, showRouteQuery, readRoute, readQueryString) import Network.Wai.Middleware.Routes.Class (Route, RenderRoute, ParseRoute, RouteAttrs(..)) import Network.Wai.Middleware.Routes.ContentTypes (contentType, contentTypeFromFile, typeHtml, typeJson, typePlain, typeCss, typeJavascript) @@ -62,33 +71,34 @@ import Control.Monad.Loops (unfoldWhileM) import Control.Monad.State (StateT, get, put, modify, runStateT, MonadState, MonadIO, lift, liftIO, MonadTrans) -import Control.Applicative (Applicative, (<$>))+import Control.Applicative (Applicative, (<$>), (<*>))  import Data.Maybe (maybe) import Data.ByteString (ByteString) import qualified Data.ByteString as B import qualified Data.ByteString.Lazy as BL-import Blaze.ByteString.Builder (Builder, toByteString, fromLazyByteString)+import Blaze.ByteString.Builder (Builder, toByteString, fromByteString) import Network.HTTP.Types.Header (HeaderName(), RequestHeaders) import Network.HTTP.Types.Status (Status(), status200) -import Data.Aeson (ToJSON, FromJSON, eitherDecode)+import Data.Aeson (ToJSON, FromJSON, eitherDecodeStrict)+ import qualified Data.Aeson as A+import qualified Data.Aeson.Encode as AE  import Data.Set (Set) import qualified Data.Set as S (empty, map) -import Data.Text.Lazy (Text)-import qualified Data.Text as TS (Text)-import qualified Data.Text.Lazy as T-import Data.Text.Lazy.Encoding (encodeUtf8)-import Data.Text.Encoding (decodeUtf8)+import Data.Text (Text)+import Data.Text.Encoding (encodeUtf8, decodeUtf8)  import Data.CaseInsensitive (CI, mk) -import Web.Cookie (Cookies, parseCookies, renderCookies, renderSetCookie, SetCookie(..))+import Web.Cookie (CookiesText, parseCookiesText, renderSetCookie, SetCookie(..)) import Data.Default.Class (def) +import qualified Network.Wai.Parse as P+ -- | The internal implementation of the HandlerM monad -- TODO: Should change this to StateT over ReaderT (but performance may suffer) newtype HandlerMI sub master m a = H { extractH :: StateT (HandlerState sub master) m a }@@ -97,33 +107,81 @@ -- | The HandlerM Monad type HandlerM sub master a = HandlerMI sub master IO a --- | A HandlerMM is a HandlerM Monad for use with a top level site (where the sub and master datatypes are the same)-type HandlerMM master a = HandlerM master master a+-- | Modeled after Network.Wai.Parse.FileInfo, but uses Text for names, and lazy ByteString for content+data FileInfo = FileInfo+  { fileName        :: Text+  , fileContentType :: Text+  , fileContent     :: BL.ByteString+  } +-- Post Params+-- Files are read into memory+-- TODO: Check for security issues. Allow automatic storing of files on disk.+type PostParams = ([(Text, Text)], [(Text, FileInfo)])++-- Private+-- Convert from Network.Wai.Parse ([Param], [File y])  to PostParams+_toPostParams :: ([P.Param], [P.File BL.ByteString])  -> PostParams+_toPostParams (params, files) = (params', files')+  where+    params' = map (\(k,v) -> (decodeUtf8 k, decodeUtf8 v))     params+    files'  = map (\(k,v) -> (decodeUtf8 k, decodeFileInfo v)) files+    decodeFileInfo fi = FileInfo+      { fileName = decodeUtf8 $ P.fileName fi+      , fileContentType = decodeUtf8 $ P.fileContentType fi+      , fileContent = P.fileContent fi+      }++-- A Raw Response handler :: source -> sink -> IO+type RespRawHandler = IO B.ByteString -> (B.ByteString -> IO ()) -> IO ()+ -- | The state kept in a HandlerM Monad data HandlerState sub master = HandlerState-                { getMaster      :: master-                , getRequestData :: RequestData sub-                -- TODO: Experimental-                -- Streaming request body, consumed, and stored as a ByteString-                , reqBody        :: Maybe BL.ByteString-                , respHeaders    :: [(HeaderName, ByteString)]-                , respStatus     :: Status-                , respResp       :: MkResponse-                , respCookies    :: [SetCookie]-                , getSub         :: sub-                , toMasterRoute  :: Route sub -> Route master-                }+  { getMaster      :: master+  , getRequestData :: RequestData sub+  -- TODO: Experimental+  -- Streaming request body, consumed, and stored as a ByteString+  , reqBody        :: Maybe ByteString+  , respHeaders    :: [(HeaderName, ByteString)]+  , respStatus     :: Status+  , respResp       :: MkResponse+  , respRaw        :: Maybe RespRawHandler+  , respCookies    :: [SetCookie]+  , getSub         :: sub+  , toMasterRoute  :: Route sub -> Route master+  -- TODO: Experimental+  -- Parsed POST request body, in the same format as Network.Wai.Parse+  , postParams     :: Maybe PostParams+  } +-- Initial Handler State+defaultHandlerState :: Env sub master -> RequestData sub -> HandlerState sub master+defaultHandlerState env req = HandlerState+  { getMaster = envMaster env+  , getRequestData = req+  , reqBody = Nothing+  , respHeaders = []+  , respStatus = status200+  , respResp = defaultResponse+  , respRaw = Nothing+  , respCookies = []+  , getSub = envSub env+  , toMasterRoute = envToMaster env+  , postParams = Nothing+  }+ -- Internal: Type of response -- Similar to Wai's Response type data MkResponse     = ResponseFile FilePath (Maybe FilePart)     | ResponseBuilder Builder     | ResponseStream StreamingBody-    -- Experimental: ResponseNext is the default, so if you don't respond in one handler, move to next automatically     | ResponseNext +-- Default response in case none is set by the handler+defaultResponse :: MkResponse+defaultResponse = ResponseBuilder ""+ -- The header name for request cookies cookieHeaderName :: CI ByteString cookieHeaderName = mk "Cookie"@@ -135,34 +193,45 @@ -- | "Run" HandlerM, resulting in a Handler runHandlerM :: HandlerM sub master () -> HandlerS sub master runHandlerM h env req hh = do-  (_, st) <- runStateT (extractH h) (HandlerState (envMaster env) req Nothing [] status200 ResponseNext [] (envSub env) (envToMaster env))+  (_, st) <- runStateT (extractH h) (defaultHandlerState env req)   -- Handle cookies (add them to headers)   let cookieHeaders = map mkSetCookie (respCookies st)-  let st' = st {respHeaders = cookieHeaders ++ (respHeaders st)}-  -- Construct response-  mkResponse st' (respResp st')+  st <- return $ st {respHeaders = cookieHeaders ++ (respHeaders st)}+  case respResp st of+    -- Abort handling current response and move to next handler+    ResponseNext -> runNext (getRequestData st) hh+    -- Normal handling+    normalResponse -> do+      -- Construct the normal response+      let resp = mkResponse st normalResponse+      -- Check if we are trying to send a raw response+      case respRaw st of+        Nothing -> hh resp+        Just rawHandler ->+          -- TODO: Ensure the body has not been read before using raw response+          hh $ responseRaw rawHandler resp   where     mkSetCookie s = (cookieSetHeaderName, toByteString $ renderSetCookie s)-    mkResponse st (ResponseFile path part) = hh $ responseFile (respStatus st) (respHeaders st) path part-    mkResponse st (ResponseBuilder builder) = hh $ responseBuilder (respStatus st) (respHeaders st) builder-    mkResponse st (ResponseStream streaming) = hh $ responseStream (respStatus st) (respHeaders st) streaming-    mkResponse st ResponseNext = runNext (getRequestData st) hh+    mkResponse st (ResponseFile path part) = responseFile (respStatus st) (respHeaders st) path part+    mkResponse st (ResponseBuilder builder) = responseBuilder (respStatus st) (respHeaders st) builder+    mkResponse st (ResponseStream streaming) = responseStream (respStatus st) (respHeaders st) streaming --- | Get the request body as a lazy bytestring. However consumes the entire body at once.+-- | Get the request body as a bytestring. Consumes the entire body into memory at once. -- TODO: Implement streaming. Prevent clash with direct use of `Network.Wai.requestBody`-rawBody :: HandlerM master master BL.ByteString+rawBody :: HandlerM sub master ByteString rawBody = do   s <- get   case reqBody s of     Just consumedBody -> return consumedBody     Nothing -> do       req <- request-      rbody <- liftIO $ readStrictRequestBody req+      rbody <- liftIO $ BL.toStrict <$> _readStrictRequestBody req       put s {reqBody = Just rbody}       return rbody -readStrictRequestBody :: Request -> IO BL.ByteString-readStrictRequestBody =+-- PRIVATE+_readStrictRequestBody :: Request -> IO BL.ByteString+_readStrictRequestBody = #if MIN_VERSION_wai(3,0,1)         -- Use the `strictRequestBody` function available in wai > 3.0.1         strictRequestBody@@ -172,8 +241,8 @@ #endif  -- | Parse the body as a JSON object-jsonBody :: FromJSON a => HandlerM master master (Either String a)-jsonBody = liftM eitherDecode rawBody+jsonBody :: FromJSON a => HandlerM sub master (Either String a)+jsonBody = liftM eitherDecodeStrict rawBody  -- | Get the master master :: HandlerM sub master master@@ -187,11 +256,21 @@ request :: HandlerM sub master Request request = liftM (waiReq . getRequestData) get +-- | Is this a websocket request+isWebsocket :: HandlerM sub master Bool+isWebsocket = liftM (maybe False (== "websocket")) (reqHeader "upgrade")+ -- | Get a particular request header (Case insensitive)-reqHeader :: ByteString -> HandlerM sub master (Maybe ByteString)-reqHeader name = liftM (lookup $ mk name) reqHeaders+reqHeader :: Text -> HandlerM sub master (Maybe Text)+reqHeader name = liftM (fmap decodeUtf8) (_reqHeaderBS nameText)+  where+    nameText = mk $ encodeUtf8 name --- | Get all request headers (Case insensitive)+-- PRIVATE+_reqHeaderBS :: CI ByteString -> HandlerM sub master (Maybe ByteString)+_reqHeaderBS name = liftM (lookup name) reqHeaders++-- | Get all request headers as raw case-insensitive bytestrings reqHeaders :: HandlerM sub master RequestHeaders reqHeaders = liftM requestHeaders request @@ -203,47 +282,47 @@ maybeRootRoute :: HandlerM sub master (Maybe (Route master)) maybeRootRoute = do   s <- get-  return $ fmap (toMasterRoute s) $ currentRoute $ getRequestData s+  return $ toMasterRoute s <$> currentRoute (getRequestData s)  -- | Get the route rendering function for the master site-showRouteMaster :: RenderRoute master => HandlerM sub master (Route master -> TS.Text)+showRouteMaster :: RenderRoute master => HandlerM sub master (Route master -> Text) showRouteMaster = return showRoute  -- | Get the route rendering function for the subsite-showRouteSub :: RenderRoute master => HandlerM sub master (Route sub -> TS.Text)+showRouteSub :: RenderRoute master => HandlerM sub master (Route sub -> Text) showRouteSub = do   s <- get   return $ showRoute . toMasterRoute s  -- | Get the route rendering function for the master site-showRouteQueryMaster :: RenderRoute master => HandlerM sub master (Route master -> [(TS.Text,TS.Text)] -> TS.Text)+showRouteQueryMaster :: RenderRoute master => HandlerM sub master (Route master -> [(Text,Text)] -> Text) showRouteQueryMaster = return showRouteQuery  -- | Get the route rendering function for the subsite-showRouteQuerySub :: RenderRoute master => HandlerM sub master (Route sub -> [(TS.Text,TS.Text)] -> TS.Text)+showRouteQuerySub :: RenderRoute master => HandlerM sub master (Route sub -> [(Text,Text)] -> Text) showRouteQuerySub = do   s <- get   return $ showRouteQuery . toMasterRoute s  -- | Get the route parsing function for the master site-readRouteMaster :: ParseRoute master => HandlerM sub master (TS.Text -> Maybe (Route master))+readRouteMaster :: ParseRoute master => HandlerM sub master (Text -> Maybe (Route master)) readRouteMaster = return readRoute  -- | Get the route parsing function for the subsite-readRouteSub :: ParseRoute sub => HandlerM sub master (TS.Text -> Maybe (Route master))+readRouteSub :: ParseRoute sub => HandlerM sub master (Text -> Maybe (Route master)) readRouteSub = do   s <- get-  return $ fmap (toMasterRoute s) . readRoute+  return $ (toMasterRoute s <$>) . readRoute  -- | Get the current route attributes routeAttrSet :: RouteAttrs sub => HandlerM sub master (Set Text)-routeAttrSet = liftM (S.map T.fromStrict . maybe S.empty routeAttrs . currentRoute . getRequestData) get+routeAttrSet = liftM (maybe S.empty routeAttrs . currentRoute . getRequestData) get  -- | Get the attributes for the current root route rootRouteAttrSet :: RouteAttrs master => HandlerM sub master (Set Text) rootRouteAttrSet = do   s <- get-  return $ S.map T.fromStrict $ maybe S.empty (routeAttrs . toMasterRoute s) $ currentRoute $ getRequestData s+  return $ maybe S.empty (routeAttrs . toMasterRoute s) $ currentRoute $ getRequestData s  -- | Add a header to the application response -- TODO: Differentiate between setting and adding headers@@ -283,10 +362,14 @@     addStream st = _setResp st $ ResponseStream s  -- | Set the response body-raw :: BL.ByteString -> HandlerM sub master ()-raw bs = modify addBody+raw :: ByteString -> HandlerM sub master ()+raw = rawBuilder . fromByteString++-- | Set the response body as a builder+rawBuilder :: Builder -> HandlerM sub master ()+rawBuilder b = modify addBody   where-    addBody st = _setResp st $ ResponseBuilder (fromLazyByteString bs)+    addBody st = _setResp st $ ResponseBuilder b  -- | Run the next application next :: HandlerM sub master ()@@ -296,12 +379,10 @@  -- Util -- Set the response handler--- Experimental: Don't overwrite previous response handler _setResp :: HandlerState sub master -> MkResponse -> HandlerState sub master-_setResp st r = case respResp st of-  ResponseNext -> st{respResp=r}-  _ -> st+_setResp st r = st{respResp=r} + -- Standard response bodies  -- | Set the body of the response to the JSON encoding of the given value. Also sets \"Content-Type\"@@ -309,7 +390,13 @@ json :: ToJSON a => a -> HandlerM sub master () json a = do   header contentType typeJson-  raw $ A.encode a+  rawBuilder $ _encode $ A.toJSON a+  where+#if MIN_VERSION_aeson(0,9,0)+    _encode = AE.encodeToBuilder+#else+    _encode = AE.encodeToByteStringBuilder+#endif  -- | Set the body of the response to the given 'Text' value. Also sets \"Content-Type\" -- header to \"text/plain\".@@ -346,17 +433,90 @@     setCookie st = st {respCookies = s : respCookies st}  -- | Get all cookies-getCookies :: HandlerM sub master Cookies+getCookies :: HandlerM sub master CookiesText getCookies = do   -- Note: We don't cache the parsedCookies for all requests to avoid overhead   -- However it is pretty easy to cache cookies in the app itself-  cookies <- reqHeader "Cookie"+  cookies <- _reqHeaderBS cookieHeaderName   return $ case cookies of     Nothing -> []-    Just cookies' -> parseCookies cookies'+    Just cookies' -> parseCookiesText cookies'  -- | Get a particular cookie-getCookie :: ByteString -> HandlerM sub master (Maybe ByteString)+getCookie :: Text -> HandlerM sub master (Maybe Text) getCookie name = do   cookies <- getCookies   return $ lookup name cookies++-- PRIVATE+-- Get the cached post params (if any)+_getCachedPostParams :: HandlerM sub master (Maybe PostParams)+_getCachedPostParams = postParams <$> get++-- PRIVATE+-- Util: Parse and cache post params+_populatePostParams :: HandlerM sub master PostParams+_populatePostParams = do+  st <- get+  case postParams st of+    Just params -> return params+    Nothing -> do+      req <- request+      params <- case P.getRequestBodyType req of+        Nothing -> return ([],[])+        Just _ -> do+          -- TODO: Use cached request body instead of reading it from wai request+          params <- liftIO $ P.parseRequestBody P.lbsBackEnd req+          return $ _toPostParams params+      put $ st{postParams=Just params}+      return params++-- PRIVATE+-- Get a list of post parameters+_getAllFileOrPostParams :: HandlerM sub master PostParams+_getAllFileOrPostParams = do+  cachedPostParams <- _getCachedPostParams+  case cachedPostParams of+    Nothing -> _populatePostParams+    Just params -> return params++-- | Get all Query params+getQueryParams :: HandlerM sub master [(Text,Text)]+getQueryParams = readQueryString . queryString <$> request++-- | Get a particular Query param+getQueryParam :: Text -> HandlerM sub master (Maybe Text)+getQueryParam name = lookup name <$> getQueryParams++-- | Get all Post params+getPostParams :: HandlerM sub master [(Text,Text)]+getPostParams = do+  (params,_) <- _getAllFileOrPostParams+  return params++-- | Get a particular Post param+getPostParam :: Text -> HandlerM sub master (Maybe Text)+getPostParam name = lookup name <$> getPostParams++-- | Get all File params+getFileParams :: HandlerM sub master [(Text,FileInfo)]+getFileParams = do+  (_,files) <- _getAllFileOrPostParams+  return files++-- | Get a particular File param+getFileParam :: Text -> HandlerM sub master (Maybe FileInfo)+getFileParam name = lookup name <$> getFileParams++-- | Get all params (query or post, NOT file)+-- Duplicate parameters are preserved+getParams :: HandlerM sub master [(Text, Text)]+getParams = (++) <$> getQueryParams <*> getPostParams++-- | Get a param (query or post, NOT file)+getParam :: Text -> HandlerM sub master (Maybe Text)+getParam name = do+  getLookup <- getQueryParam name+  case getLookup of+    Nothing -> getPostParam name+    Just _ -> return $ getLookup
src/Network/Wai/Middleware/Routes/Monad.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE OverloadedStrings, GeneralizedNewtypeDeriving, TypeFamilies, RankNTypes, DeriveFunctor #-}+{-# LANGUAGE OverloadedStrings, TypeFamilies, RankNTypes, DeriveFunctor #-}  {- | Module      :  Network.Wai.Middleware.Routes.Monad@@ -15,6 +15,9 @@     ( -- * Route Monad       RouteM       -- * Compose Routes+    , DefaultMaster(..)+    , Route(DefaultRoute)+    , handler     , middleware     , route     , catchall@@ -27,7 +30,8 @@  import Network.Wai import Network.Wai.Middleware.Routes.Routes-import Network.HTTP.Types+import Network.Wai.Middleware.Routes.DefaultRoute+import Network.HTTP.Types (status404)  import Util.Free (F(..), liftF) @@ -47,10 +51,17 @@ defaultAction = catchall  -- | Add a middleware to the application--- Middleware are ordered so the one declared earlier is wraps the remaining application.+-- Middleware are ordered so the one declared earlier wraps the ones later middleware :: Middleware -> RouteM () middleware m = liftF $ M m () +-- | Add a wai-routes handler+handler :: Handler DefaultMaster -> RouteM ()+handler h = middleware $ customRouteDispatch dispatcher' DefaultMaster+  where+    dispatcher' env req = runHandler h env (Just $ DefaultRoute $ getRoute req) req+    getRoute req = (pathInfo $ waiReq req, readQueryString $ queryString $ waiReq req)+ -- | Add a route to the application. -- Routes are ordered so the one declared earlier is matched first. route :: (Routable master master) => master -> RouteM ()@@ -66,7 +77,7 @@ waiApp :: RouteM () -> Application waiApp (F r) = r (const defaultApplication) f   where-    f (M m r) = m r+    f (M m r') = m r'     f (D a) = a  -- | Similar to waiApp but returns the app in an arbitrary monad
src/Network/Wai/Middleware/Routes/Routes.hs view
@@ -3,6 +3,7 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TypeSynonymInstances, FlexibleInstances #-} {-# LANGUAGE TemplateHaskell, QuasiQuotes #-}+{-# LANGUAGE RankNTypes #-} {- | Module      :  Network.Wai.Middleware.Routes.Routes Copyright   :  (c) Anupam Jain 2013@@ -29,6 +30,7 @@      -- * Dispatch     , routeDispatch+    , customRouteDispatch      -- * URL rendering and parsing     , showRoute@@ -57,12 +59,15 @@     , currentRoute           -- | Extract the current `Route` from `RequestData`     , runNext                -- | Run the next application in the stack +    -- * Not exported outside wai-routes+    , runHandler+    , readQueryString     )     where  -- Wai import Network.Wai (ResponseReceived, Middleware, Application, pathInfo, requestMethod, requestMethod, Response, Request(..))-import Network.HTTP.Types (decodePath, encodePath, queryTextToQuery, queryToQueryText)+import Network.HTTP.Types (Query, decodePath, encodePath, queryTextToQuery, queryToQueryText)  -- Network.Wai.Middleware.Routes import Network.Wai.Middleware.Routes.Class (Route, RenderRoute(..), ParseRoute(..), RouteAttrs(..))@@ -107,14 +112,14 @@ runNext req = nextApp req $ waiReq req  -- | A `Handler` generates an App from the master datatype-type Handler master = HandlerS master master+type Handler sub = forall master. RenderRoute master => HandlerS sub master type HandlerS sub master = Env sub master -> App sub  -- | Generates everything except `Routable` instance and dispatch function mkRouteData :: String -> [ResourceTree String] -> Q [Dec] mkRouteData typName routes = do   let typ = parseType typName-  let rname = mkName $ "resources" ++ typName+  let rname = mkName $ "_resources" ++ typName   let resourceTrees = map (fmap parseType) routes   eres <- lift routes   let resourcesDec =@@ -159,7 +164,7 @@   let typ = parseType typName   disp <- mkDispatchClause MkDispatchSettings         { mdsRunHandler    = [| runHandler    |]-        , mdsSubDispatcher = [| subDispatcher  |]+        , mdsSubDispatcher = [| subDispatcher |]         , mdsGetPathInfo   = [| getPathInfo   |]         , mdsMethod        = [| getReqMethod  |]         , mdsSetPathInfo   = [| setPathInfo   |]@@ -189,9 +194,15 @@  -- | Generates the application middleware from a `Routable` master datatype routeDispatch :: Routable master master => master -> Middleware+routeDispatch = customRouteDispatch dispatcher++-- | Like routeDispatch but generates the application middleware from a custom dispatcher+customRouteDispatch :: HandlerS master master -> master -> Middleware+-- TODO: Should this have master master instead of sub master?+-- TODO: Verify that this plays well with subsites -- Env master master is converted to Env sub master by subDispatcher -- Route information is filled in by runHandler-routeDispatch master def req = dispatcher (_masterToEnv master) RequestData{waiReq=req, nextApp=def, currentRoute=Nothing}+customRouteDispatch customDispatcher master def req = customDispatcher (_masterToEnv master) RequestData{waiReq=req, nextApp=def, currentRoute=Nothing}  -- | Render a `Route` and Query parameters to Text showRouteQuery :: RenderRoute master => Route master -> [(Text,Text)] -> Text@@ -209,8 +220,12 @@ -- | Read a route from Text -- Returns Nothing if Route reading failed. Just route otherwise readRoute :: ParseRoute master => Text -> Maybe (Route master)-readRoute = parseRoute . second (map (second (fromMaybe "")) . queryToQueryText) . decodePath . encodeUtf8+readRoute = parseRoute . second readQueryString . decodePath . encodeUtf8 +-- | Convert a Query to the format expected by parseRoute+readQueryString :: Query -> [(Text, Text)]+readQueryString = map (second (fromMaybe "")) . queryToQueryText+ -- PRIVATE  -- Get the request method from a RequestData@@ -236,6 +251,8 @@ app405 _master = runNext  -- Run a route handler function+-- Currently all this does is populate the route into RequestData+-- But it may do more in the future runHandler     :: HandlerS sub master     -> Env sub master@@ -255,8 +272,8 @@   where     env' = _envToSub getSub toMasterRoute env     reqData' = reqData{currentRoute=Nothing}-    qq (k,mv) = (decodeUtf8 k, maybe "" decodeUtf8 mv)-    req = waiReq reqData+    -- qq (k,mv) = (decodeUtf8 k, maybe "" decodeUtf8 mv)+    -- req = waiReq reqData  _masterToEnv :: master -> Env master master _masterToEnv master = Env master master id
wai-routes.cabal view
@@ -1,14 +1,14 @@-name          : wai-routes-version       : 0.8.1-cabal-version : >=1.18-build-type    : Simple-license       : MIT-license-file  : LICENSE-maintainer    : ajnsit@gmail.com-stability     : Experimental-homepage      : https://ajnsit.github.io/wai-routes/-synopsis      : Typesafe URLs for Wai applications.-description   : Provides easy to use typesafe URLs for Wai Applications. See README for more information. Also see examples/ directory for usage examples.+name               : wai-routes+version            : 0.9.0+cabal-version      : >=1.18+build-type         : Simple+license            : MIT+license-file       : LICENSE+maintainer         : ajnsit@gmail.com+stability          : Experimental+homepage           : https://ajnsit.github.io/wai-routes/+synopsis           : Typesafe URLs for Wai applications.+description        : Provides easy to use typesafe URLs for Wai Applications. See README for more information. Also see examples/ directory for usage examples. category           : Network author             : Anupam Jain data-dir           : ""@@ -20,59 +20,63 @@  source-repository this     type     : git-    location : http://github.com/ajnsit/wai-routes/tree/v0.8.1-    tag      : v0.8.1+    location : http://github.com/ajnsit/wai-routes/tree/v0.9.0+    tag      : v0.9.0  library-    build-depends: base               >= 4.7  && < 4.9-                 , wai                >= 3.0  && < 3.1-                 , text               >= 1.2  && < 1.3-                 , template-haskell   >= 2.9  && < 2.11-                 , mtl                >= 2.1  && < 2.3-                 , aeson              >= 0.8  && < 0.10-                 , containers         >= 0.5  && < 0.6-                 , random             >= 1.1  && < 1.2-                 , path-pieces        >= 0.2  && < 0.3-                 , bytestring         >= 0.10 && < 0.11-                 , http-types         >= 0.8  && < 0.9-                 , blaze-builder      >= 0.4  && < 0.5-                 , monad-loops        >= 0.4  && < 0.5-                 , case-insensitive   >= 1.2  && < 1.3-                 , mime-types         >= 0.1  && < 0.2-                 , filepath           >= 1.3  && < 1.5-                 , cookie             >= 0.4  && < 0.5-                 , data-default-class >= 0.0  && < 0.1-    exposed-modules: Network.Wai.Middleware.Routes-                     Network.Wai.Middleware.Routes.Parse-                     Network.Wai.Middleware.Routes.Overlap-                     Network.Wai.Middleware.Routes.Class-                     Network.Wai.Middleware.Routes.Routes-                     Network.Wai.Middleware.Routes.Monad-                     Network.Wai.Middleware.Routes.Handler-                     Network.Wai.Middleware.Routes.ContentTypes-                     Network.Wai.Middleware.Routes.TH-                     Network.Wai.Middleware.Routes.TH.Types-                     Network.Wai.Middleware.Routes.TH.Dispatch-                     Network.Wai.Middleware.Routes.TH.ParseRoute-                     Network.Wai.Middleware.Routes.TH.RenderRoute-                     Network.Wai.Middleware.Routes.TH.RouteAttrs-                     Util.Free-    exposed        : True-    buildable      : True-    hs-source-dirs : src+    build-depends      : base               >= 4.7  && < 4.9+                       , wai                >= 3.0  && < 3.1+                       , wai-extra          >= 3.0  && < 3.1+                       , wai-app-static     >= 3.0  && < 3.2+                       , text               >= 1.2  && < 1.3+                       , template-haskell   >= 2.9  && < 2.11+                       , mtl                >= 2.1  && < 2.3+                       , aeson              >= 0.8  && < 0.11+                       , containers         >= 0.5  && < 0.6+                       , random             >= 1.1  && < 1.2+                       , path-pieces        >= 0.2  && < 0.3+                       , bytestring         >= 0.10 && < 0.11+                       , http-types         >= 0.8  && < 0.9+                       , blaze-builder      >= 0.4  && < 0.5+                       , monad-loops        >= 0.4  && < 0.5+                       , case-insensitive   >= 1.2  && < 1.3+                       , mime-types         >= 0.1  && < 0.2+                       , filepath           >= 1.3  && < 1.5+                       , cookie             >= 0.4  && < 0.5+                       , data-default-class >= 0.0  && < 0.1+    exposed-modules    : Network.Wai.Middleware.Routes+    other-modules      : Network.Wai.Middleware.Routes.Parse+                         Network.Wai.Middleware.Routes.Overlap+                         Network.Wai.Middleware.Routes.Class+                         Network.Wai.Middleware.Routes.Routes+                         Network.Wai.Middleware.Routes.Monad+                         Network.Wai.Middleware.Routes.Handler+                         Network.Wai.Middleware.Routes.ContentTypes+                         Network.Wai.Middleware.Routes.DefaultRoute+                         Network.Wai.Middleware.Routes.TH+                         Network.Wai.Middleware.Routes.TH.Types+                         Network.Wai.Middleware.Routes.TH.Dispatch+                         Network.Wai.Middleware.Routes.TH.ParseRoute+                         Network.Wai.Middleware.Routes.TH.RenderRoute+                         Network.Wai.Middleware.Routes.TH.RouteAttrs+                         Util.Free+    exposed            : True+    buildable          : True+    hs-source-dirs     : src     default-language   : Haskell2010  test-suite test-  main-is:             Spec.hs-  type:                exitcode-stdio-1.0-  default-language:    Haskell2010-  hs-source-dirs:      test-  GHC-options:         -Wall -threaded -fno-warn-orphans+  main-is          : Spec.hs+  type             : exitcode-stdio-1.0+  default-language : Haskell2010+  hs-source-dirs   : test+  GHC-options      : -Wall -threaded -fno-warn-orphans -  build-depends: base           >= 4.7 && < 4.9-               , wai            >= 3.0 && < 3.1-               , aeson          >= 0.8 && < 0.10-               , hspec          >= 2.1 && < 2.3-               , hspec-wai      >= 0.6 && < 0.7-               , hspec-wai-json >= 0.6 && < 0.7-               , wai-routes+  build-depends    : base           >= 4.7 && < 4.9+                   , wai            >= 3.0 && < 3.1+                   , aeson          >= 0.8 && < 0.11+                   , hspec          >= 2.1 && < 2.3+                   , hspec-wai      >= 0.6 && < 0.7+                   , hspec-wai-json >= 0.6 && < 0.7+                   , wai-app-static >= 3.0 && < 3.2+                   , wai-routes