apiary 0.4.3.2 → 0.5.0.0
raw patch · 14 files changed
+551/−192 lines, 14 filesdep +taggeddep ~basePVP ok
version bump matches the API change (PVP)
Dependencies added: tagged
Dependency ranges changed: base
API changes (from Hackage documentation)
- Control.Monad.Apiary.Filter: function :: Monad m => (SList c -> Request -> Maybe (SList c')) -> ApiaryT c' m b -> ApiaryT c m b
- Control.Monad.Apiary.Filter: function' :: Monad m => (Request -> Maybe a) -> ApiaryT (Snoc as a) m b -> ApiaryT as m b
- Control.Monad.Apiary.Filter.Capture: Equal :: Text -> Equal
- Control.Monad.Apiary.Filter.Capture: Fetch :: Fetch a
- Control.Monad.Apiary.Filter.Capture: capture :: (Capture as, Monad m) => SList as -> ApiaryT (CaptureResult xs as) m b -> ApiaryT xs m b
- Control.Monad.Apiary.Filter.Capture: capture' :: Capture as => SList as -> [Text] -> SList xs -> Maybe (SList (CaptureResult xs as))
- Control.Monad.Apiary.Filter.Capture: captureElem :: CaptureElem a => a -> Text -> SList xs -> Maybe (SList (Next a xs))
- Control.Monad.Apiary.Filter.Capture: class CaptureElem a where type family Next a (xs :: [*]) :: [*]
- Control.Monad.Apiary.Filter.Capture: data Equal
- Control.Monad.Apiary.Filter.Capture: data Fetch a
- Control.Monad.Apiary.Filter.Capture: instance CaptureElem Equal
- Control.Monad.Apiary.Filter.Capture: instance Param a => CaptureElem (Fetch a)
- Control.Monad.Apiary.Filter.Capture: type Capture as = All CaptureElem as
- Data.Apiary.Param: class Param a
- Data.Apiary.Param: instance Param Char
- Data.Apiary.Param: instance Param Double
- Data.Apiary.Param: instance Param Float
- Data.Apiary.Param: instance Param Int
- Data.Apiary.Param: instance Param Int16
- Data.Apiary.Param: instance Param Int32
- Data.Apiary.Param: instance Param Int64
- Data.Apiary.Param: instance Param Int8
- Data.Apiary.Param: instance Param Integer
- Data.Apiary.Param: instance Param String
- Data.Apiary.Param: instance Param Text
- Data.Apiary.Param: instance Param Word
- Data.Apiary.Param: instance Param Word16
- Data.Apiary.Param: instance Param Word32
- Data.Apiary.Param: instance Param Word64
- Data.Apiary.Param: instance Param Word8
- Data.Apiary.Param: readParam :: Param a => Text -> Maybe a
- Web.Apiary.TH: capture :: QuasiQuoter
+ Control.Monad.Apiary.Filter: (=!:) :: (Query a, Monad m) => ByteString -> Proxy a -> ApiaryT (Snoc as a) m b -> ApiaryT as m b
+ Control.Monad.Apiary.Filter: (=*:) :: (Query a, Monad m) => ByteString -> Proxy a -> ApiaryT (Snoc as [a]) m b -> ApiaryT as m b
+ Control.Monad.Apiary.Filter: (=+:) :: (Query a, Monad m) => ByteString -> Proxy a -> ApiaryT (Snoc as [a]) m b -> ApiaryT as m b
+ Control.Monad.Apiary.Filter: (=:) :: (Query a, Monad m) => ByteString -> Proxy a -> ApiaryT (Snoc as a) m b -> ApiaryT as m b
+ Control.Monad.Apiary.Filter: (=?:) :: (Query a, Monad m) => ByteString -> Proxy a -> ApiaryT (Snoc as (Maybe a)) m b -> ApiaryT as m b
+ Control.Monad.Apiary.Filter: (?:) :: (Query a, Monad m) => ByteString -> Proxy a -> ApiaryT as m b -> ApiaryT as m b
+ Control.Monad.Apiary.Filter: capture :: QuasiQuoter
+ Control.Monad.Apiary.Filter: http09 :: Monad m => ApiaryT c m b -> ApiaryT c m b
+ Control.Monad.Apiary.Filter: http10 :: Monad m => ApiaryT c m b -> ApiaryT c m b
+ Control.Monad.Apiary.Filter: http11 :: Monad m => ApiaryT c m b -> ApiaryT c m b
+ Control.Monad.Apiary.Filter: httpVersion :: Monad m => HttpVersion -> ApiaryT c m b -> ApiaryT c m b
+ Control.Monad.Apiary.Filter.Internal: function :: Monad m => (SList c -> Request -> Maybe (SList c')) -> ApiaryT c' m b -> ApiaryT c m b
+ Control.Monad.Apiary.Filter.Internal: function' :: Monad m => (Request -> Maybe a) -> ApiaryT (Snoc as a) m b -> ApiaryT as m b
+ Control.Monad.Apiary.Filter.Internal: function_ :: Monad m => (Request -> Bool) -> ApiaryT c m b -> ApiaryT c m b
+ Control.Monad.Apiary.Filter.Internal.Capture: Equal :: Text -> Equal
+ Control.Monad.Apiary.Filter.Internal.Capture: capture :: (Capture as, Monad m) => SList as -> ApiaryT (CaptureResult xs as) m b -> ApiaryT xs m b
+ Control.Monad.Apiary.Filter.Internal.Capture: capture' :: Capture as => SList as -> [Text] -> SList xs -> Maybe (SList (CaptureResult xs as))
+ Control.Monad.Apiary.Filter.Internal.Capture: captureElem :: CaptureElem a => a -> Text -> SList xs -> Maybe (SList (Next a xs))
+ Control.Monad.Apiary.Filter.Internal.Capture: class CaptureElem a where type family Next a (xs :: [*]) :: [*]
+ Control.Monad.Apiary.Filter.Internal.Capture: data Equal
+ Control.Monad.Apiary.Filter.Internal.Capture: instance CaptureElem Equal
+ Control.Monad.Apiary.Filter.Internal.Capture: instance Path a => CaptureElem (Fetch a)
+ Control.Monad.Apiary.Filter.Internal.Capture: type Capture as = All CaptureElem as
+ Control.Monad.Apiary.Filter.Internal.Capture: type Fetch = Proxy
+ Control.Monad.Apiary.Filter.Internal.Query: class Strategy (w :: * -> *) where type family SNext w (as :: [*]) a :: [*]
+ Control.Monad.Apiary.Filter.Internal.Query: data Check a
+ Control.Monad.Apiary.Filter.Internal.Query: data First a
+ Control.Monad.Apiary.Filter.Internal.Query: data Many a
+ Control.Monad.Apiary.Filter.Internal.Query: data One a
+ Control.Monad.Apiary.Filter.Internal.Query: data Option a
+ Control.Monad.Apiary.Filter.Internal.Query: data Some a
+ Control.Monad.Apiary.Filter.Internal.Query: getQuery :: Query a => Proxy (w a) -> ByteString -> Query -> [Maybe a]
+ Control.Monad.Apiary.Filter.Internal.Query: instance Strategy Check
+ Control.Monad.Apiary.Filter.Internal.Query: instance Strategy First
+ Control.Monad.Apiary.Filter.Internal.Query: instance Strategy Many
+ Control.Monad.Apiary.Filter.Internal.Query: instance Strategy One
+ Control.Monad.Apiary.Filter.Internal.Query: instance Strategy Option
+ Control.Monad.Apiary.Filter.Internal.Query: instance Strategy Some
+ Control.Monad.Apiary.Filter.Internal.Query: query :: (Query a, Strategy w, Monad m) => ByteString -> Proxy (w a) -> ApiaryT (SNext w as a) m b -> ApiaryT as m b
+ Control.Monad.Apiary.Filter.Internal.Query: readStrategy :: (Strategy w, Query a) => ByteString -> Proxy (w a) -> Query -> SList as -> Maybe (SList (SNext w as a))
+ Data.Apiary.Param: class Path a
+ Data.Apiary.Param: class Query a
+ Data.Apiary.Param: instance Path ByteString
+ Data.Apiary.Param: instance Path Char
+ Data.Apiary.Param: instance Path Double
+ Data.Apiary.Param: instance Path Float
+ Data.Apiary.Param: instance Path Int
+ Data.Apiary.Param: instance Path Int16
+ Data.Apiary.Param: instance Path Int32
+ Data.Apiary.Param: instance Path Int64
+ Data.Apiary.Param: instance Path Int8
+ Data.Apiary.Param: instance Path Integer
+ Data.Apiary.Param: instance Path String
+ Data.Apiary.Param: instance Path Text
+ Data.Apiary.Param: instance Path Word
+ Data.Apiary.Param: instance Path Word16
+ Data.Apiary.Param: instance Path Word32
+ Data.Apiary.Param: instance Path Word64
+ Data.Apiary.Param: instance Path Word8
+ Data.Apiary.Param: instance Query ()
+ Data.Apiary.Param: instance Query ByteString
+ Data.Apiary.Param: instance Query Double
+ Data.Apiary.Param: instance Query Float
+ Data.Apiary.Param: instance Query Int
+ Data.Apiary.Param: instance Query Int16
+ Data.Apiary.Param: instance Query Int32
+ Data.Apiary.Param: instance Query Int64
+ Data.Apiary.Param: instance Query Int8
+ Data.Apiary.Param: instance Query Integer
+ Data.Apiary.Param: instance Query String
+ Data.Apiary.Param: instance Query Text
+ Data.Apiary.Param: instance Query Word
+ Data.Apiary.Param: instance Query Word16
+ Data.Apiary.Param: instance Query Word32
+ Data.Apiary.Param: instance Query Word64
+ Data.Apiary.Param: instance Query Word8
+ Data.Apiary.Param: instance Query a => Query (Maybe a)
+ Data.Apiary.Param: pByteString :: Proxy ByteString
+ Data.Apiary.Param: pDouble :: Proxy Double
+ Data.Apiary.Param: pFloat :: Proxy Float
+ Data.Apiary.Param: pInt :: Proxy Int
+ Data.Apiary.Param: pInt16 :: Proxy Int16
+ Data.Apiary.Param: pInt32 :: Proxy Int32
+ Data.Apiary.Param: pInt64 :: Proxy Int64
+ Data.Apiary.Param: pInt8 :: Proxy Int8
+ Data.Apiary.Param: pInteger :: Proxy Integer
+ Data.Apiary.Param: pLazyByteString :: Proxy ByteString
+ Data.Apiary.Param: pLazyText :: Proxy Text
+ Data.Apiary.Param: pMaybe :: Proxy a -> Proxy (Maybe a)
+ Data.Apiary.Param: pString :: Proxy String
+ Data.Apiary.Param: pText :: Proxy Text
+ Data.Apiary.Param: pVoid :: Proxy ()
+ Data.Apiary.Param: pWord :: Proxy Word
+ Data.Apiary.Param: pWord32 :: Proxy Word32
+ Data.Apiary.Param: pWord64 :: Proxy Word64
+ Data.Apiary.Param: pWord8 :: Proxy Word8
+ Data.Apiary.Param: readPath :: Path a => Text -> Maybe a
+ Data.Apiary.Param: readQuery :: Query a => Maybe ByteString -> Maybe a
Files
- apiary.cabal +21/−8
- src/Control/Monad/Apiary.hs +0/−3
- src/Control/Monad/Apiary/Action/Internal.hs +5/−1
- src/Control/Monad/Apiary/Filter.hs +150/−46
- src/Control/Monad/Apiary/Filter/Capture.hs +0/−62
- src/Control/Monad/Apiary/Filter/Internal.hs +22/−0
- src/Control/Monad/Apiary/Filter/Internal/Capture.hs +64/−0
- src/Control/Monad/Apiary/Filter/Internal/Capture/TH.hs +40/−0
- src/Control/Monad/Apiary/Filter/Internal/Query.hs +125/−0
- src/Data/Apiary/Param.hs +112/−24
- src/Web/Apiary.hs +5/−3
- src/Web/Apiary/TH.hs +0/−5
- src/Web/Apiary/TH/Internal.hs +0/−39
- test/main.hs +7/−1
apiary.cabal view
@@ -1,5 +1,5 @@ name: apiary-version: 0.4.3.2+version: 0.5.0.0 x-revision: 1 synopsis: Simple web framework inspired by scotty. description:@@ -15,12 +15,23 @@ . main :: IO () main = run 3000 . runApiary def $ do-   [capture|/:Int|] . queryFirst' "name" . stdMethod GET . action $ \\age name -> do+   [capture|/:Int|] . ("name" =: pLazyByteString) . stdMethod GET . action $ \\age name -> do       guard (age >= 18)       contentType "text/html"-       lbs . L.concat $ ["<h1>Hello, ", L.fromStrict name, "!</h1>"]+       lbs . L.concat $ ["<h1>Hello, ", name, "!</h1>\\n"] @ .+ @+ $ curl localhost:3000+ 404 Page Notfound.+ $ curl 'localhost:3000/20?name=arice'+ <h1>Hello, arice!</h1>+ $ curl 'localhost:3000/15?name=bob'+ 404 Page Notfound.+ $ curl -XPOST 'localhost:3000/20?name=arice'+ 404 Page Notfound.+ @+ . * Nestable route handling(ApiaryT Monad; capture, stdMethod and more.). . * type safe route filter.@@ -42,19 +53,20 @@ library exposed-modules: Web.Apiary- Web.Apiary.TH Control.Monad.Apiary Control.Monad.Apiary.Filter- Control.Monad.Apiary.Filter.Capture+ Control.Monad.Apiary.Filter.Internal+ Control.Monad.Apiary.Filter.Internal.Capture+ Control.Monad.Apiary.Filter.Internal.Query Control.Monad.Apiary.Action Data.Apiary.SList Data.Apiary.Param - other-modules: Web.Apiary.TH.Internal- Control.Monad.Apiary.Internal+ other-modules: Control.Monad.Apiary.Internal Control.Monad.Apiary.Action.Internal+ Control.Monad.Apiary.Filter.Internal.Capture.TH other-extensions: KindSignatures , DataKinds , TypeOperators@@ -76,6 +88,7 @@ , conduit >=1.1 && <1.2 , monad-logger >=0.3 && <0.4 , data-default-class >=0.0 && <0.1+ , tagged >=0.7 && <0.8 , http-types >=0.8 && <0.9 , mime-types >=0.1 && <0.2@@ -89,7 +102,7 @@ test-suite test-framework main-is: main.hs type: exitcode-stdio-1.0- build-depends: base >=4.5 && <4.8+ build-depends: base >=4.6 && <4.8 , test-framework >=0.8 && <0.9 , test-framework-hunit >=0.3 && <0.4 , wai >=2.1 && <2.2
src/Control/Monad/Apiary.hs view
@@ -7,9 +7,6 @@ , apiaryConfig -- * execute action , action, action_, actionWithPreAction- -- * Reexport- , module Control.Monad.Apiary.Filter ) where import Control.Monad.Apiary.Internal-import Control.Monad.Apiary.Filter
src/Control/Monad/Apiary/Action/Internal.hs view
@@ -42,7 +42,7 @@ instance Default ApiaryConfig where def = ApiaryConfig { notFound = \_ -> return $ responseLBS status404 - [("Content-Type", "text/plain")] "404 Page Notfound."+ [("Content-Type", "text/plain")] "404 Page Notfound.\n" , defaultStatus = ok200 , defaultHeader = [] , rootPattern = ["", "/", "/index.html", "/index.htm"]@@ -201,8 +201,12 @@ getQuery' :: Monad m => S.ByteString -> ActionT m (Maybe S.ByteString) getQuery' q = getQuery q >>= maybe mzero return +{-# DEPRECATED getQuery' "use qeury derived filter." #-}+ getQuery :: Monad m => S.ByteString -> ActionT m (Maybe (Maybe S.ByteString)) getQuery q = (lookup q . queryString) `liftM` getRequest++{-# DEPRECATED getQuery "use qeury derived filter." #-} status :: Monad m => Status -> ActionT m () status st = modifyState (\s -> s { actionStatus = st } )
src/Control/Monad/Apiary/Filter.hs view
@@ -3,54 +3,177 @@ {-# LANGUAGE TypeOperators #-} {-# LANGUAGE DataKinds #-} -module Control.Monad.Apiary.Filter- ( method, stdMethod, root+module Control.Monad.Apiary.Filter (+ -- * filters+ -- ** http method+ method, stdMethod+ -- ** http version+ , Control.Monad.Apiary.Filter.httpVersion+ , http09, http10, http11+ -- ** path matcher+ , root+ , capture++ -- ** query matcher+ , (=:), (=!:), (=?:), (?:), (=*:), (=+:)+ , hasQuery++ -- ** other , ssl- -- * query parameter- -- ** query getter(always success)- , queryMany, queryMany'- , maybeQueryFirst, maybeQueryFirst'- -- ** query filter- , querySome, querySome'- , queryFirst, queryFirst'- -- * low level- , function, function'+ -- * Reexport -- StdMethod(..) , module Network.HTTP.Types -- * deprecated- , hasQuery, queryAll, queryAll'+ , queryAll, queryAll'+ , querySome, querySome'+ , queryFirst, queryFirst'+ , queryMany, queryMany'+ , maybeQueryFirst, maybeQueryFirst' ) where import Control.Monad-import Network.Wai-import qualified Network.HTTP.Types as Use+import Network.Wai as Wai+import qualified Network.HTTP.Types as HT import Network.HTTP.Types (StdMethod(..)) import qualified Data.ByteString as S import Data.Maybe+import Data.Proxy import Data.Apiary.SList+import Data.Apiary.Param import Control.Monad.Apiary.Action.Internal+import Control.Monad.Apiary.Filter.Internal+import Control.Monad.Apiary.Filter.Internal.Query+import Control.Monad.Apiary.Filter.Internal.Capture.TH import Control.Monad.Apiary.Internal --- | raw and most generic filter function.-function :: Monad m => (SList c -> Request -> Maybe (SList c')) -> ApiaryT c' m b -> ApiaryT c m b-function f = focus $ \r c -> case f c r of- Nothing -> mzero- Just c' -> return c'+ssl :: Monad m => ApiaryT c m a -> ApiaryT c m a+ssl = function_ isSecure --- | filter and append argument.-function' :: Monad m => (Request -> Maybe a) -> ApiaryT (Snoc as a) m b -> ApiaryT as m b-function' f = function $ \c r -> sSnoc c `fmap` f r+-- | http version filter. since 0.5.0.0.+httpVersion :: Monad m => HT.HttpVersion -> ApiaryT c m b -> ApiaryT c m b+httpVersion v = function_ $ (v ==) . Wai.httpVersion --- | filter only(not modify arguments).-function_ :: Monad m => (Request -> Bool) -> ApiaryT c m b -> ApiaryT c m b-function_ f = function $ \c r -> if f r then Just c else Nothing+-- | http/0.9 only accepted fiter. since 0.5.0.0.+http09 :: Monad m => ApiaryT c m b -> ApiaryT c m b+http09 = Control.Monad.Apiary.Filter.httpVersion HT.http09 -ssl :: Monad m => ApiaryT c m a -> ApiaryT c m a-ssl = function_ isSecure+-- | http/1.0 only accepted fiter. since 0.5.0.0.+http10 :: Monad m => ApiaryT c m b -> ApiaryT c m b+http10 = Control.Monad.Apiary.Filter.httpVersion HT.http10 +-- | http/1.1 only accepted fiter. since 0.5.0.0.+http11 :: Monad m => ApiaryT c m b -> ApiaryT c m b+http11 = Control.Monad.Apiary.Filter.httpVersion HT.http11++method :: Monad m => HT.Method -> ApiaryT c m a -> ApiaryT c m a+method m = function_ ((m ==) . requestMethod)++stdMethod :: Monad m => StdMethod -> ApiaryT c m a -> ApiaryT c m a+stdMethod = method . HT.renderStdMethod++-- | filter by 'Control.Monad.Apiary.Action.rootPattern' of 'Control.Monad.Apiary.Action.ApiaryConfig'.+root :: Monad m => ApiaryT c m b -> ApiaryT c m b+root m = do+ rs <- rootPattern `liftM` apiaryConfig+ function_ (\r -> rawPathInfo r `elem` rs) m++-- | get first matched paramerer. since 0.5.0.0.+--+-- @+-- "key" =: pInt == query "key" (Proxy :: Proxy (First Int))+-- @+(=:) :: (Query a, Monad m)+ => S.ByteString -> Proxy a -> ApiaryT (Snoc as a) m b -> ApiaryT as m b+k =: t = query k (asFirst t)+ where+ asFirst :: Proxy a -> Proxy (First a)+ asFirst _ = Proxy+++-- | get one matched paramerer. since 0.5.0.0.+--+-- when more one parameger given, not matched.+--+-- @+-- "key" =: pInt == query "key" (Proxy :: Proxy (One Int))+-- @+(=!:) :: (Query a, Monad m)+ => S.ByteString -> Proxy a -> ApiaryT (Snoc as a) m b -> ApiaryT as m b+k =!: t = query k (asOne t)+ where+ asOne :: Proxy a -> Proxy (One a)+ asOne _ = Proxy++-- | get optional first paramerer. since 0.5.0.0.+--+-- when illegal type parameter given, fail mather(don't give Nothing).+--+-- @+-- "key" =: pInt == query "key" (Proxy :: Proxy (Option Int))+-- @+(=?:) :: (Query a, Monad m)+ => S.ByteString -> Proxy a -> ApiaryT (Snoc as (Maybe a)) m b -> ApiaryT as m b+k =?: t = query k (asOption t)+ where+ asOption :: Proxy a -> Proxy (Option a)+ asOption _ = Proxy++-- | check parameger given and type. since 0.5.0.0.+--+-- If you wan't to allow any type, give 'pVoid'.+--+-- @+-- "key" =: pInt == query "key" (Proxy :: Proxy (Check Int))+-- @+(?:) :: (Query a, Monad m)+ => S.ByteString -> Proxy a -> ApiaryT as m b -> ApiaryT as m b+k ?: t = query k (asCheck t)+ where+ asCheck :: Proxy a -> Proxy (Check a)+ asCheck _ = Proxy++-- | get many paramerer. since 0.5.0.0.+--+-- @+-- "key" =: pInt == query "key" (Proxy :: Proxy (Many Int))+-- @+(=*:) :: (Query a, Monad m)+ => S.ByteString -> Proxy a -> ApiaryT (Snoc as [a]) m b -> ApiaryT as m b+k =*: t = query k (asMany t)+ where+ asMany :: Proxy a -> Proxy (Many a)+ asMany _ = Proxy++-- | get some paramerer. since 0.5.0.0.+--+-- @+-- "key" =: pInt == query "key" (Proxy :: Proxy (Some Int))+-- @+(=+:) :: (Query a, Monad m)+ => S.ByteString -> Proxy a -> ApiaryT (Snoc as [a]) m b -> ApiaryT as m b+k =+: t = query k (asSome t)+ where+ asSome :: Proxy a -> Proxy (Some a)+ asSome _ = Proxy++-- | query exists checker.+--+-- @+-- hasQuery q = 'query' q (Proxy :: Proxy ('Check' ()))+-- @+--+hasQuery :: Monad m => S.ByteString -> ApiaryT c m a -> ApiaryT c m a+hasQuery q = query q (Proxy :: Proxy (Check ()))++--------------------------------------------------------------------------------++{-# DEPRECATED queryMany, querySome, queryAll, queryMany', querySome', queryAll'+ , maybeQueryFirst, queryFirst, maybeQueryFirst'+ , queryFirst' "use query related filters" #-}+ -- | get [0,) parameters by query parameter allows empty value. since 0.4.3.0. queryMany :: Monad m => S.ByteString -> ApiaryT (Snoc as [Maybe S.ByteString]) m b@@ -70,7 +193,6 @@ -> ApiaryT (Snoc as [Maybe S.ByteString]) m b -- ^ Nothing == no value paramator. -> ApiaryT as m b queryAll = querySome-{-# DEPRECATED queryAll "use querySome" #-} -- | get [0,) parameters by query parameter not allows empty value. since 0.4.3.0. queryMany' :: Monad m => S.ByteString@@ -91,7 +213,6 @@ -> ApiaryT (Snoc as [S.ByteString]) m b -> ApiaryT as m b queryAll' = querySome'-{-# DEPRECATED queryAll' "use querySome'" #-} -- | get first query parameter allow empty value. since 0.4.3.0, maybeQueryFirst :: Monad m => S.ByteString@@ -116,20 +237,3 @@ -> ApiaryT (Snoc as S.ByteString) m b -> ApiaryT as m b queryFirst' q = function' $ listToMaybe . mapMaybe snd . filter ((q ==) . fst) . queryString--hasQuery :: Monad m => S.ByteString -> ApiaryT c m a -> ApiaryT c m a-hasQuery q = function_ (any ((q ==) . fst) . queryString)--{-# DEPRECATED hasQuery "use query* function." #-}--method :: Monad m => Use.Method -> ApiaryT c m a -> ApiaryT c m a-method m = function_ ((m ==) . requestMethod)--stdMethod :: Monad m => StdMethod -> ApiaryT c m a -> ApiaryT c m a-stdMethod = method . Use.renderStdMethod---- | filter by 'Control.Monad.Apiary.Action.rootPattern' of 'Control.Monad.Apiary.Action.ApiaryConfig'.-root :: Monad m => ApiaryT c m b -> ApiaryT c m b-root m = do- rs <- rootPattern `liftM` apiaryConfig- function_ (\r -> rawPathInfo r `elem` rs) m
− src/Control/Monad/Apiary/Filter/Capture.hs
@@ -1,62 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE ConstraintKinds #-}-{-# LANGUAGE Rank2Types #-}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE NoMonomorphismRestriction #-}-{-# LANGUAGE UndecidableInstances #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE ScopedTypeVariables #-}--module Control.Monad.Apiary.Filter.Capture where--import Network.Wai--import Control.Applicative-import qualified Data.Text as T-import Data.Apiary.Param-import Data.Apiary.SList--import Control.Monad.Apiary--data Equal = Equal T.Text-data Fetch a = Fetch--class CaptureElem a where- type Next a (xs :: [*]) :: [*]- captureElem :: a -> T.Text -> SList xs -> Maybe (SList (Next a xs))--instance CaptureElem Equal where- type Next Equal xs = xs- captureElem (Equal s) p c | s == p = Just c- | otherwise = Nothing--instance Param a => CaptureElem (Fetch a) where- type Next (Fetch a) xs = (xs `Snoc` a)- captureElem (Fetch :: Fetch a) p c = (sSnoc c) <$> (readParam p :: Maybe a)---type Capture as = All CaptureElem as--type family CaptureResult (bf :: [*]) (as :: [*]) :: [*]-type instance CaptureResult bf '[] = bf-type instance CaptureResult bf (a ': as) = (CaptureResult (Next a bf) as)--capture' :: Capture as => SList as -> [T.Text] -> SList xs -> Maybe (SList (CaptureResult xs as))-capture' SNil [] bf = Just bf-capture' (c ::: cs) (p:ps) bf = captureElem c p bf >>= capture' cs ps-capture' SNil _ _ = Nothing-capture' _ [] _ = Nothing---- | low level (without Template Haskell) capture. since 0.4.2.0------ @--- myCapture :: SList '[Equal, Fetch Int, Fetch String]--- myCapture = Equal "path" ::: (Fetch :: Fetch Int) ::: (Fetch :: Fetch String) ::: SNil------ capture myCapture . stdMethod GET . action $ \age name -> do--- yourAction--- @-capture :: (Capture as, Monad m) => SList as -> ApiaryT (CaptureResult xs as) m b -> ApiaryT xs m b-capture cap = function $ \bf req -> capture' cap (pathInfo req) bf
+ src/Control/Monad/Apiary/Filter/Internal.hs view
@@ -0,0 +1,22 @@+module Control.Monad.Apiary.Filter.Internal where++import Control.Monad+import Control.Monad.Apiary.Internal+import Network.Wai+import Data.Apiary.SList++-- | raw and most generic filter function.+function :: Monad m => (SList c -> Request -> Maybe (SList c')) -> ApiaryT c' m b -> ApiaryT c m b+function f = focus $ \r c -> case f c r of+ Nothing -> mzero+ Just c' -> return c'++-- | filter and append argument.+function' :: Monad m => (Request -> Maybe a) -> ApiaryT (Snoc as a) m b -> ApiaryT as m b+function' f = function $ \c r -> sSnoc c `fmap` f r++-- | filter only(not modify arguments).+function_ :: Monad m => (Request -> Bool) -> ApiaryT c m b -> ApiaryT c m b+function_ f = function $ \c r -> if f r then Just c else Nothing++
+ src/Control/Monad/Apiary/Filter/Internal/Capture.hs view
@@ -0,0 +1,64 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE Rank2Types #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE NoMonomorphismRestriction #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeSynonymInstances #-}++module Control.Monad.Apiary.Filter.Internal.Capture where++import Network.Wai++import Control.Applicative+import qualified Data.Text as T+import Data.Apiary.Param+import Data.Apiary.SList+import Data.Proxy++import Control.Monad.Apiary+import Control.Monad.Apiary.Filter.Internal++data Equal = Equal T.Text+type Fetch = Proxy++class CaptureElem a where+ type Next a (xs :: [*]) :: [*]+ captureElem :: a -> T.Text -> SList xs -> Maybe (SList (Next a xs))++instance CaptureElem Equal where+ type Next Equal xs = xs+ captureElem (Equal s) p c | s == p = Just c+ | otherwise = Nothing++instance Path a => CaptureElem (Fetch a) where+ type Next (Fetch a) xs = (xs `Snoc` a)+ captureElem (Proxy :: Fetch a) p c = (sSnoc c) <$> (readPath p :: Maybe a)++type Capture as = All CaptureElem as++type family CaptureResult (bf :: [*]) (as :: [*]) :: [*]+type instance CaptureResult bf '[] = bf+type instance CaptureResult bf (a ': as) = (CaptureResult (Next a bf) as)++capture' :: Capture as => SList as -> [T.Text] -> SList xs -> Maybe (SList (CaptureResult xs as))+capture' SNil [] bf = Just bf+capture' (c ::: cs) (p:ps) bf = captureElem c p bf >>= capture' cs ps+capture' SNil _ _ = Nothing+capture' _ [] _ = Nothing++-- | low level (without Template Haskell) capture. since 0.4.2.0+--+-- @+-- myCapture :: 'SList' '['Equal', 'Fetch' Int, Fetch String]+-- myCapture = 'Equal' "path" ':::' 'pInt' ::: 'pString' ::: 'SNil'+--+-- capture myCapture . stdMethod GET . action $ \age name -> do+-- yourAction+-- @+capture :: (Capture as, Monad m) => SList as -> ApiaryT (CaptureResult xs as) m b -> ApiaryT xs m b+capture cap = function $ \bf req -> capture' cap (pathInfo req) bf
+ src/Control/Monad/Apiary/Filter/Internal/Capture/TH.hs view
@@ -0,0 +1,40 @@+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE OverloadedStrings #-}+module Control.Monad.Apiary.Filter.Internal.Capture.TH where++import Language.Haskell.TH+import Language.Haskell.TH.Quote+import qualified Control.Monad.Apiary.Filter.Internal.Capture as Capture+import Data.Apiary.SList+import qualified Data.Text as T+import Data.Proxy++preCap :: String -> [String]+preCap "" = []+preCap "/" = []+preCap ('/':p) = splitPath p+preCap p = splitPath p++splitPath :: String -> [String]+splitPath = map T.unpack . T.splitOn "/" . T.pack++mkCap :: [String] -> ExpQ+mkCap [] = [|SNil|]+mkCap ((':':tyStr):as) = do+ -- ty <- lookupTypeName tyStr >>= maybe (fail "") return+ let ty = mkName tyStr+ [|(Proxy :: Capture.Fetch $(conT ty)) ::: $(mkCap as) |]+mkCap (eq:as) = do+ [|(Capture.Equal $(stringE eq)) ::: $(mkCap as) |]++applyCapture :: ExpQ -> ExpQ+applyCapture e = [|Capture.capture $e|]++capture :: QuasiQuoter+capture = QuasiQuoter + { quoteExp = applyCapture . mkCap . preCap+ , quotePat = \_ -> error "No quotePat."+ , quoteType = \_ -> error "No quoteType."+ , quoteDec = \_ -> error "No quoteDec."+ }+
+ src/Control/Monad/Apiary/Filter/Internal/Query.hs view
@@ -0,0 +1,125 @@+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE UndecidableInstances #-}++{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE NoMonomorphismRestriction #-}++module Control.Monad.Apiary.Filter.Internal.Query where++import Control.Monad.Apiary+import Control.Monad.Apiary.Filter.Internal+import Data.Apiary.Param+import Data.Apiary.SList++import Network.Wai+import qualified Network.HTTP.Types as HTTP++import qualified Data.ByteString as S+import Data.Maybe+import Data.Proxy++-- | low level query getter. since 0.5.0.0.+--+-- @+-- query "key" (Proxy :: Proxy (fetcher type))+-- @+--+-- examples:+--+-- @+-- query "key" (Proxy :: Proxy ('First' Int)) -- get first \'key\' query parameter as Int.+-- query "key" (Proxy :: Proxy ('Option' (Maybe Int)) -- get first \'key\' query parameter as Int. allow without param or value.+-- query "key" (Proxy :: Proxy ('Many' String) -- get all \'key\' query parameter as String.+-- @+-- +query :: (Query a, Strategy w, Monad m)+ => S.ByteString+ -> Proxy (w a)+ -> ApiaryT (SNext w as a) m b+ -> ApiaryT as m b+query k p = function $ \l r -> readStrategy k p (queryString r) l++--------------------------------------------------------------------------------++class Strategy (w :: * -> *) where+ type SNext w (as :: [*]) a :: [*]+ readStrategy :: Query a => S.ByteString -> Proxy (w a)+ -> HTTP.Query -> SList as -> Maybe (SList (SNext w as a))++getQuery :: Query a => Proxy (w a) -> S.ByteString -> HTTP.Query -> [Maybe a]+getQuery _ k = map readQuery . map snd . filter ((k ==) . fst)++-- | get first matched key( [1,) params to Type.). since 0.5.0.0.+data Option a+instance Strategy Option where+ type SNext Option as a = Snoc as (Maybe a)+ readStrategy k p q l =+ let rs = getQuery p k q+ in if any isNothing rs+ then Nothing+ else case catMaybes rs of+ [] -> Just $ sSnoc l (Nothing `asMaybe` p)+ a:_ -> Just $ sSnoc l (Just a)+ where+ asMaybe :: Maybe a -> Proxy (w a) -> Maybe a+ asMaybe a _ = asProxyTypeOf a Proxy++-- | get first matched key ( [0,) params to Maybe Type.) since 0.5.0.0.+data First a+instance Strategy First where+ type SNext First as a = Snoc as a+ readStrategy k p q l =+ let rs = getQuery p k q+ in if any isNothing rs+ then Nothing+ else case catMaybes rs of+ [] -> Nothing+ a:_ -> Just $ sSnoc l a++-- | get key ( [1] param to Type.) since 0.5.0.0.+data One a+instance Strategy One where+ type SNext One as a = Snoc as a+ readStrategy k p q l =+ let rs = getQuery p k q+ in if any isNothing rs+ then Nothing+ else case catMaybes rs of+ [a] -> Just $ sSnoc l a+ _ -> Nothing++-- | get parameters ( [0,) params to [Type] ) since 0.5.0.0.+data Many a+instance Strategy Many where+ type SNext Many as a = Snoc as [a]+ readStrategy k p q l =+ let rs = getQuery p k q+ in if any isNothing rs+ then Nothing+ else Just $ sSnoc l (catMaybes rs)++-- | get parameters ( [1,) params to [Type] ) since 0.5.0.0.+data Some a+instance Strategy Some where+ type SNext Some as a = Snoc as [a]+ readStrategy k p q l =+ let rs = getQuery p k q+ in if any isNothing rs+ then Nothing+ else case catMaybes rs of+ [] -> Nothing+ as -> Just $ sSnoc l as++-- | type check ( [0,) params to No argument ) since 0.5.0.0.+data Check a+instance Strategy Check where+ type SNext Check as a = as+ readStrategy k p q l =+ let rs = getQuery p k q+ in if any isNothing rs+ then Nothing+ else case catMaybes rs of+ [] -> Nothing+ _ -> Just l
src/Data/Apiary/Param.hs view
@@ -1,43 +1,131 @@ {-# LANGUAGE TypeSynonymInstances #-} {-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE NoMonomorphismRestriction #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE UndecidableInstances #-} module Data.Apiary.Param where import qualified Data.Text as T+import qualified Data.Text.Encoding as T import qualified Data.Text.Lazy as TL+import qualified Data.Text.Lazy.Encoding as TL+import qualified Data.ByteString.Char8 as S+import qualified Data.ByteString.Lazy.Char8 as L+import Data.Text.Encoding.Error import Text.Read import Data.Int import Data.Word+import Data.Proxy -class Param a where- readParam :: T.Text -> Maybe a+class Path a where+ readPath :: T.Text -> Maybe a -instance Param Char where- readParam s | T.null s = Nothing- | otherwise = Just $ T.head s+instance Path Char where+ readPath s | T.null s = Nothing+ | otherwise = Just $ T.head s -instance Param Int where readParam = readMaybe . T.unpack-instance Param Int8 where readParam = readMaybe . T.unpack-instance Param Int16 where readParam = readMaybe . T.unpack-instance Param Int32 where readParam = readMaybe . T.unpack-instance Param Int64 where readParam = readMaybe . T.unpack-instance Param Integer where readParam = readMaybe . T.unpack+instance Path Int where readPath = readMaybe . T.unpack+instance Path Int8 where readPath = readMaybe . T.unpack+instance Path Int16 where readPath = readMaybe . T.unpack+instance Path Int32 where readPath = readMaybe . T.unpack+instance Path Int64 where readPath = readMaybe . T.unpack+instance Path Integer where readPath = readMaybe . T.unpack -instance Param Word where readParam = readMaybe . T.unpack-instance Param Word8 where readParam = readMaybe . T.unpack-instance Param Word16 where readParam = readMaybe . T.unpack-instance Param Word32 where readParam = readMaybe . T.unpack-instance Param Word64 where readParam = readMaybe . T.unpack+instance Path Word where readPath = readMaybe . T.unpack+instance Path Word8 where readPath = readMaybe . T.unpack+instance Path Word16 where readPath = readMaybe . T.unpack+instance Path Word32 where readPath = readMaybe . T.unpack+instance Path Word64 where readPath = readMaybe . T.unpack -instance Param Double where readParam = readMaybe . T.unpack-instance Param Float where readParam = readMaybe . T.unpack+instance Path Double where readPath = readMaybe . T.unpack+instance Path Float where readPath = readMaybe . T.unpack -instance Param T.Text where- readParam = Just+instance Path T.Text where readPath = Just+instance Path TL.Text where readPath = Just . TL.fromStrict+instance Path S.ByteString where readPath = Just . T.encodeUtf8+instance Path L.ByteString where readPath = Just . TL.encodeUtf8 . TL.fromStrict+instance Path String where readPath = Just . T.unpack -instance Param TL.Text where- readParam = Just . TL.fromStrict+-------------------------------------------------------------------------------- -instance Param String where- readParam = Just . T.unpack+class Query a where+ readQuery :: Maybe S.ByteString -> Maybe a +instance Query Int where readQuery = maybe Nothing (readMaybe . S.unpack)+instance Query Int8 where readQuery = maybe Nothing (readMaybe . S.unpack)+instance Query Int16 where readQuery = maybe Nothing (readMaybe . S.unpack)+instance Query Int32 where readQuery = maybe Nothing (readMaybe . S.unpack)+instance Query Int64 where readQuery = maybe Nothing (readMaybe . S.unpack)+instance Query Integer where readQuery = maybe Nothing (readMaybe . S.unpack)++instance Query Word where readQuery = maybe Nothing (readMaybe . S.unpack)+instance Query Word8 where readQuery = maybe Nothing (readMaybe . S.unpack)+instance Query Word16 where readQuery = maybe Nothing (readMaybe . S.unpack)+instance Query Word32 where readQuery = maybe Nothing (readMaybe . S.unpack)+instance Query Word64 where readQuery = maybe Nothing (readMaybe . S.unpack)++instance Query Double where readQuery = maybe Nothing (readMaybe . S.unpack)+instance Query Float where readQuery = maybe Nothing (readMaybe . S.unpack)++instance Query T.Text where readQuery = fmap $ T.decodeUtf8With lenientDecode+instance Query TL.Text where readQuery = fmap (TL.decodeUtf8With lenientDecode . L.fromStrict)+instance Query S.ByteString where readQuery = id+instance Query L.ByteString where readQuery = fmap L.fromStrict+instance Query String where readQuery = fmap S.unpack++-- | allow no parameter. but check parameter type.+instance Query a => Query (Maybe a) where+ readQuery (Just a) = Just `fmap` readQuery (Just a)+ readQuery Nothing = Just Nothing++-- | always success. for exists check.+instance Query () where+ readQuery _ = Just ()++pInt :: Proxy Int+pInt = Proxy++pInt8 :: Proxy Int8+pInt8 = Proxy+pInt16 :: Proxy Int16+pInt16 = Proxy+pInt32 :: Proxy Int32+pInt32 = Proxy+pInt64 :: Proxy Int64+pInt64 = Proxy+pInteger :: Proxy Integer+pInteger = Proxy++pWord :: Proxy Word+pWord = Proxy+pWord8 :: Proxy Word8+pWord8 = Proxy+pWord32 :: Proxy Word32+pWord32 = Proxy+pWord64 :: Proxy Word64+pWord64 = Proxy++pDouble :: Proxy Double+pDouble = Proxy+pFloat :: Proxy Float+pFloat = Proxy++pText :: Proxy T.Text+pText = Proxy+pLazyText :: Proxy TL.Text+pLazyText = Proxy+pByteString :: Proxy S.ByteString+pByteString = Proxy+pLazyByteString :: Proxy L.ByteString+pLazyByteString = Proxy+pString :: Proxy String+pString = Proxy++pVoid :: Proxy ()+pVoid = Proxy++pMaybe :: Proxy a -> Proxy (Maybe a)+pMaybe _ = Proxy
src/Web/Apiary.hs view
@@ -2,7 +2,9 @@ ( module Control.Monad.Apiary , module Control.Monad.Apiary.Action- , module Web.Apiary.TH+ , module Control.Monad.Apiary.Filter+ , module Data.Apiary.Param+ -- * reexports -- | MonadIO , module Control.Monad.Trans -- | MonadPlus(..), msum, mfilter, guard@@ -11,8 +13,8 @@ import Control.Monad.Apiary import Control.Monad.Apiary.Action-import Web.Apiary.TH+import Data.Apiary.Param import Control.Monad.Trans(MonadIO(..)) import Control.Monad (MonadPlus(..), msum, mfilter, guard)-+import Control.Monad.Apiary.Filter
− src/Web/Apiary/TH.hs
@@ -1,5 +0,0 @@-module Web.Apiary.TH- ( capture- ) where--import Web.Apiary.TH.Internal
− src/Web/Apiary/TH/Internal.hs
@@ -1,39 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE OverloadedStrings #-}-module Web.Apiary.TH.Internal where--import Language.Haskell.TH-import Language.Haskell.TH.Quote-import Control.Monad.Apiary.Filter.Capture hiding(capture, capture')-import qualified Control.Monad.Apiary.Filter.Capture as Capture-import Data.Apiary.SList-import qualified Data.Text as T--preCap :: String -> [String]-preCap "" = []-preCap "/" = []-preCap ('/':p) = splitPath p-preCap p = splitPath p--splitPath :: String -> [String]-splitPath = map T.unpack . T.splitOn "/" . T.pack--mkCap :: [String] -> ExpQ-mkCap [] = [|SNil|]-mkCap ((':':tyStr):as) = do- -- ty <- lookupTypeName tyStr >>= maybe (fail "") return- let ty = mkName tyStr- [|(Fetch :: Fetch $(conT ty)) ::: $(mkCap as) |]-mkCap (eq:as) = do- [|(Equal $(stringE eq)) ::: $(mkCap as) |]--applyCapture :: ExpQ -> ExpQ-applyCapture e = [|Capture.capture $e|]--capture :: QuasiQuoter-capture = QuasiQuoter - { quoteExp = applyCapture . mkCap . preCap- , quotePat = \_ -> error "No quotePat."- , quoteType = \_ -> error "No quoteType."- , quoteDec = \_ -> error "No quoteDec."- }
test/main.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-} import Test.Framework import Test.Framework.Providers.HUnit@@ -28,6 +29,7 @@ getNeko = setPath defaultRequest "/neko" --------------------------------------------------------------------------------+ assertPlain200 :: L.ByteString -> Application -> Request -> IO () assertPlain200 body app req = flip runSession app $ do res <- request req@@ -47,7 +49,7 @@ res <- request req assertStatus 404 res assertContentType "text/plain" res- assertBody "404 Page Notfound." res+ assertBody "404 Page Notfound.\n" res -------------------------------------------------------------------------------- @@ -111,6 +113,10 @@ ] --------------------------------------------------------------------------------+++--------------------------------------------------------------------------------+ main :: IO () main = defaultMain