apiary 0.11.3 → 0.12.0
raw patch · 14 files changed
+575/−243 lines, 14 filesdep +blaze-htmlPVP ok
version bump matches the API change (PVP)
Dependencies added: blaze-html
API changes (from Hackage documentation)
- Data.Apiary.Param: instance [overlap ok] ReqParam (FileInfo ByteString)
+ Control.Monad.Apiary: document :: Text -> ApiaryT c n m a -> ApiaryT c n m a
+ Control.Monad.Apiary: group :: Text -> ApiaryT c n m a -> ApiaryT c n m a
+ Control.Monad.Apiary: runApiaryT' :: (Monad n, Monad m) => (forall b. n b -> IO b) -> ApiaryConfig -> ApiaryT '[] n m a -> m (Application, Documents)
+ Control.Monad.Apiary.Action: File :: ByteString -> ByteString -> ByteString -> ByteString -> File
+ Control.Monad.Apiary.Action: data File
+ Control.Monad.Apiary.Action: documentAction :: ApiaryConfig -> Documents -> ActionT IO ()
+ Control.Monad.Apiary.Action: fileContent :: File -> ByteString
+ Control.Monad.Apiary.Action: fileContentType :: File -> ByteString
+ Control.Monad.Apiary.Action: fileName :: File -> ByteString
+ Control.Monad.Apiary.Action: fileParameter :: File -> ByteString
+ Control.Monad.Apiary.Action: type ContentType = ByteString
+ Control.Monad.Apiary.Filter: QueryKey :: ByteString -> Maybe Html -> QueryKey
+ Control.Monad.Apiary.Filter: data QueryKey
+ Control.Monad.Apiary.Filter: instance IsString QueryKey
+ Control.Monad.Apiary.Filter: queryDesc :: QueryKey -> Maybe Html
+ Control.Monad.Apiary.Filter: queryKey :: QueryKey -> ByteString
+ Control.Monad.Apiary.Filter.Internal.Strategy: instance Typeable1 Check
+ Control.Monad.Apiary.Filter.Internal.Strategy: instance Typeable1 First
+ Control.Monad.Apiary.Filter.Internal.Strategy: instance Typeable1 Many
+ Control.Monad.Apiary.Filter.Internal.Strategy: instance Typeable1 One
+ Control.Monad.Apiary.Filter.Internal.Strategy: instance Typeable1 Option
+ Control.Monad.Apiary.Filter.Internal.Strategy: instance Typeable1 Some
+ Control.Monad.Apiary.Filter.Internal.Strategy: instance Typeable2 LimitSome
+ Control.Monad.Apiary.Filter.Internal.Strategy: strategyRep :: Strategy w => proxy w -> StrategyRep
+ Data.Apiary.Document: DocFetch :: TypeRep -> (Maybe Html) -> Doc -> Doc
+ Data.Apiary.Document: DocGroup :: Text -> Doc -> Doc
+ Data.Apiary.Document: DocMethod :: Method -> Doc -> Doc
+ Data.Apiary.Document: DocPath :: Text -> Doc -> Doc
+ Data.Apiary.Document: DocQuery :: ByteString -> StrategyRep -> QueryRep -> Html -> Doc -> Doc
+ Data.Apiary.Document: DocRoot :: Doc -> Doc
+ Data.Apiary.Document: Document :: (Maybe Text) -> Doc
+ Data.Apiary.Document: Documents :: [PathDoc] -> [(Text, [PathDoc])] -> Documents
+ Data.Apiary.Document: End :: Route
+ Data.Apiary.Document: Fetch :: TypeRep -> (Maybe Html) -> Route -> Route
+ Data.Apiary.Document: MethodDoc :: [QueryDoc] -> Text -> MethodDoc
+ Data.Apiary.Document: Path :: Text -> Route -> Route
+ Data.Apiary.Document: PathDoc :: Route -> [(Method, MethodDoc)] -> PathDoc
+ Data.Apiary.Document: QueryDoc :: ByteString -> StrategyRep -> QueryRep -> Html -> QueryDoc
+ Data.Apiary.Document: StrategyRep :: Text -> StrategyRep
+ Data.Apiary.Document: data Doc
+ Data.Apiary.Document: data Documents
+ Data.Apiary.Document: data MethodDoc
+ Data.Apiary.Document: data PathDoc
+ Data.Apiary.Document: data QueryDoc
+ Data.Apiary.Document: data Route
+ Data.Apiary.Document: data StrategyRep
+ Data.Apiary.Document: defaultDocumentToHtml :: Documents -> Html
+ Data.Apiary.Document: docToDocument :: Doc -> Maybe (Maybe Text, PathDoc)
+ Data.Apiary.Document: docsToDocuments :: [Doc] -> Documents
+ Data.Apiary.Document: document :: MethodDoc -> Text
+ Data.Apiary.Document: groups :: Documents -> [(Text, [PathDoc])]
+ Data.Apiary.Document: instance Eq Route
+ Data.Apiary.Document: instance Eq StrategyRep
+ Data.Apiary.Document: instance Show StrategyRep
+ Data.Apiary.Document: mergeMethod :: [PathDoc] -> [PathDoc]
+ Data.Apiary.Document: methods :: PathDoc -> [(Method, MethodDoc)]
+ Data.Apiary.Document: noGroup :: Documents -> [PathDoc]
+ Data.Apiary.Document: path :: PathDoc -> Route
+ Data.Apiary.Document: queries :: MethodDoc -> [QueryDoc]
+ Data.Apiary.Document: queryDocument :: QueryDoc -> Html
+ Data.Apiary.Document: queryName :: QueryDoc -> ByteString
+ Data.Apiary.Document: queryRep :: QueryDoc -> QueryRep
+ Data.Apiary.Document: queryStrategy :: QueryDoc -> StrategyRep
+ Data.Apiary.Document: routeToHtml :: Route -> (Html, Html)
+ Data.Apiary.Document: strategyInfo :: StrategyRep -> Text
+ Data.Apiary.Param: Check :: QueryRep
+ Data.Apiary.Param: File :: ByteString -> ByteString -> ByteString -> ByteString -> File
+ Data.Apiary.Param: Nullable :: TypeRep -> QueryRep
+ Data.Apiary.Param: Strict :: TypeRep -> QueryRep
+ Data.Apiary.Param: data File
+ Data.Apiary.Param: data QueryRep
+ Data.Apiary.Param: data Text
+ Data.Apiary.Param: fileContent :: File -> ByteString
+ Data.Apiary.Param: fileContentType :: File -> ByteString
+ Data.Apiary.Param: fileName :: File -> ByteString
+ Data.Apiary.Param: fileParameter :: File -> ByteString
+ Data.Apiary.Param: instance [overlap ok] Eq File
+ Data.Apiary.Param: instance [overlap ok] Eq QueryRep
+ Data.Apiary.Param: instance [overlap ok] ReqParam File
+ Data.Apiary.Param: instance [overlap ok] Show File
+ Data.Apiary.Param: instance [overlap ok] Show QueryRep
+ Data.Apiary.Param: instance [overlap ok] Typeable File
+ Data.Apiary.Param: instance [overlap ok] Typeable Text
+ Data.Apiary.Param: pathRep :: Path a => proxy a -> TypeRep
+ Data.Apiary.Param: queryRep :: Query a => proxy a -> QueryRep
+ Data.Apiary.Param: reqParamRep :: ReqParam a => proxy a -> QueryRep
+ Data.Apiary.Param: type Param = (ByteString, ByteString)
+ Data.Apiary.Param: typeRep :: Typeable a => proxy a -> TypeRep
- Control.Monad.Apiary: action :: (Functor n, Monad n) => Fn c (ActionT n ()) -> ApiaryT c n m ()
+ Control.Monad.Apiary: action :: Monad n => Fn c (ActionT n ()) -> ApiaryT c n m ()
- Control.Monad.Apiary: action' :: (Functor n, Monad n) => (SList c -> ActionT n ()) -> ApiaryT c n m ()
+ Control.Monad.Apiary: action' :: Monad n => (SList c -> ActionT n ()) -> ApiaryT c n m ()
- Control.Monad.Apiary: actionWithPreAction :: (Functor n, Monad n) => (SList xs -> ActionT n a) -> Fn xs (ActionT n ()) -> ApiaryT xs n m ()
+ Control.Monad.Apiary: actionWithPreAction :: Monad n => (SList xs -> ActionT n a) -> Fn xs (ActionT n ()) -> ApiaryT xs n m ()
- Control.Monad.Apiary: apiaryConfig :: (Functor n, Monad n) => ApiaryT c n m ApiaryConfig
+ Control.Monad.Apiary: apiaryConfig :: Monad n => ApiaryT c n m ApiaryConfig
- Control.Monad.Apiary.Action: ApiaryConfig :: Application -> Status -> ResponseHeaders -> [ByteString] -> (FilePath -> ByteString) -> ApiaryConfig
+ Control.Monad.Apiary.Action: ApiaryConfig :: Application -> Status -> ResponseHeaders -> [ByteString] -> (FilePath -> ByteString) -> (Documents -> ActionT IO ()) -> ApiaryConfig
- Control.Monad.Apiary.Action: contentType :: Monad m => ByteString -> ActionT m ()
+ Control.Monad.Apiary.Action: contentType :: Monad m => ContentType -> ActionT m ()
- Control.Monad.Apiary.Action: getReqFiles :: MonadIO m => ActionT m [File ByteString]
+ Control.Monad.Apiary.Action: getReqFiles :: MonadIO m => ActionT m [File]
- Control.Monad.Apiary.Filter: (=!:) :: (Functor n, MonadIO n, ReqParam a) => ByteString -> proxy a -> ApiaryT (Snoc as a) n m b -> ApiaryT as n m b
+ Control.Monad.Apiary.Filter: (=!:) :: (MonadIO n, ReqParam a) => QueryKey -> proxy a -> ApiaryT (Snoc as a) n m b -> ApiaryT as n m b
- Control.Monad.Apiary.Filter: (=*:) :: (Functor n, MonadIO n, ReqParam a) => ByteString -> proxy a -> ApiaryT (Snoc as [a]) n m b -> ApiaryT as n m b
+ Control.Monad.Apiary.Filter: (=*:) :: (MonadIO n, ReqParam a) => QueryKey -> proxy a -> ApiaryT (Snoc as [a]) n m b -> ApiaryT as n m b
- Control.Monad.Apiary.Filter: (=+:) :: (Functor n, MonadIO n, ReqParam a) => ByteString -> proxy a -> ApiaryT (Snoc as [a]) n m b -> ApiaryT as n m b
+ Control.Monad.Apiary.Filter: (=+:) :: (MonadIO n, ReqParam a) => QueryKey -> proxy a -> ApiaryT (Snoc as [a]) n m b -> ApiaryT as n m b
- Control.Monad.Apiary.Filter: (=:) :: (Functor n, MonadIO n, ReqParam a) => ByteString -> proxy a -> ApiaryT (Snoc as a) n m b -> ApiaryT as n m b
+ Control.Monad.Apiary.Filter: (=:) :: (MonadIO n, ReqParam a) => QueryKey -> proxy a -> ApiaryT (Snoc as a) n m b -> ApiaryT as n m b
- Control.Monad.Apiary.Filter: (=?:) :: (Functor n, MonadIO n, ReqParam a) => ByteString -> proxy a -> ApiaryT (Snoc as (Maybe a)) n m b -> ApiaryT as n m b
+ Control.Monad.Apiary.Filter: (=?:) :: (MonadIO n, ReqParam a) => QueryKey -> proxy a -> ApiaryT (Snoc as (Maybe a)) n m b -> ApiaryT as n m b
- Control.Monad.Apiary.Filter: (?:) :: (Functor n, MonadIO n, ReqParam a) => ByteString -> proxy a -> ApiaryT as n m b -> ApiaryT as n m b
+ Control.Monad.Apiary.Filter: (?:) :: (MonadIO n, ReqParam a) => QueryKey -> proxy a -> ApiaryT as n m b -> ApiaryT as n m b
- Control.Monad.Apiary.Filter: endPath :: (Functor n, Monad n) => ApiaryT c n m a -> ApiaryT c n m a
+ Control.Monad.Apiary.Filter: endPath :: Monad n => ApiaryT c n m a -> ApiaryT c n m a
- Control.Monad.Apiary.Filter: eqHeader :: (Functor n, Monad n) => HeaderName -> ByteString -> ApiaryT as n m b -> ApiaryT as n m b
+ Control.Monad.Apiary.Filter: eqHeader :: Monad n => HeaderName -> ByteString -> ApiaryT as n m b -> ApiaryT as n m b
- Control.Monad.Apiary.Filter: fetch :: (Path a, Functor n, Monad n) => proxy a -> ApiaryT (Snoc as a) n m b -> ApiaryT as n m b
+ Control.Monad.Apiary.Filter: fetch :: (Path a, Monad n) => proxy a -> Maybe Html -> ApiaryT (Snoc as a) n m b -> ApiaryT as n m b
- Control.Monad.Apiary.Filter: hasHeader :: (Functor n, Monad n) => HeaderName -> ApiaryT as n m b -> ApiaryT as n m b
+ Control.Monad.Apiary.Filter: hasHeader :: Monad n => HeaderName -> ApiaryT as n m b -> ApiaryT as n m b
- Control.Monad.Apiary.Filter: hasQuery :: (Functor n, MonadIO n) => ByteString -> ApiaryT c n m a -> ApiaryT c n m a
+ Control.Monad.Apiary.Filter: hasQuery :: MonadIO n => QueryKey -> ApiaryT c n m a -> ApiaryT c n m a
- Control.Monad.Apiary.Filter: header :: (Functor n, Monad n) => HeaderName -> ApiaryT (Snoc as ByteString) n m b -> ApiaryT as n m b
+ Control.Monad.Apiary.Filter: header :: Monad n => HeaderName -> ApiaryT (Snoc as ByteString) n m b -> ApiaryT as n m b
- Control.Monad.Apiary.Filter: header' :: (Strategy w, Functor n, Monad n) => (forall x. Proxy x -> Proxy (w x)) -> (Header -> Bool) -> ApiaryT (SNext w as ByteString) n m b -> ApiaryT as n m b
+ Control.Monad.Apiary.Filter: header' :: (Strategy w, Monad n) => (forall x. Proxy x -> Proxy (w x)) -> (Header -> Bool) -> ApiaryT (SNext w as ByteString) n m b -> ApiaryT as n m b
- Control.Monad.Apiary.Filter: headers :: (Functor n, Monad n) => HeaderName -> ApiaryT (Snoc as [ByteString]) n m b -> ApiaryT as n m b
+ Control.Monad.Apiary.Filter: headers :: Monad n => HeaderName -> ApiaryT (Snoc as [ByteString]) n m b -> ApiaryT as n m b
- Control.Monad.Apiary.Filter: http09 :: (Functor n, Monad n) => ApiaryT c n m b -> ApiaryT c n m b
+ Control.Monad.Apiary.Filter: http09 :: Monad n => ApiaryT c n m b -> ApiaryT c n m b
- Control.Monad.Apiary.Filter: http10 :: (Functor n, Monad n) => ApiaryT c n m b -> ApiaryT c n m b
+ Control.Monad.Apiary.Filter: http10 :: Monad n => ApiaryT c n m b -> ApiaryT c n m b
- Control.Monad.Apiary.Filter: http11 :: (Functor n, Monad n) => ApiaryT c n m b -> ApiaryT c n m b
+ Control.Monad.Apiary.Filter: http11 :: Monad n => ApiaryT c n m b -> ApiaryT c n m b
- Control.Monad.Apiary.Filter: httpVersion :: (Functor n, Monad n) => HttpVersion -> ApiaryT c n m b -> ApiaryT c n m b
+ Control.Monad.Apiary.Filter: httpVersion :: Monad n => HttpVersion -> ApiaryT c n m b -> ApiaryT c n m b
- Control.Monad.Apiary.Filter: method :: (Functor n, Monad n) => Method -> ApiaryT c n m a -> ApiaryT c n m a
+ Control.Monad.Apiary.Filter: method :: Monad n => Method -> ApiaryT c n m a -> ApiaryT c n m a
- Control.Monad.Apiary.Filter: path :: (Functor n, Monad n) => Text -> ApiaryT c n m a -> ApiaryT c n m a
+ Control.Monad.Apiary.Filter: path :: Monad n => Text -> ApiaryT c n m a -> ApiaryT c n m a
- Control.Monad.Apiary.Filter: query :: (ReqParam a, Strategy w, Functor n, MonadIO n) => ByteString -> proxy (w a) -> ApiaryT (SNext w as a) n m b -> ApiaryT as n m b
+ Control.Monad.Apiary.Filter: query :: (ReqParam a, Strategy w, MonadIO n) => QueryKey -> proxy (w a) -> ApiaryT (SNext w as a) n m b -> ApiaryT as n m b
- Control.Monad.Apiary.Filter: root :: (Functor n, Monad n) => ApiaryT c n m b -> ApiaryT c n m b
+ Control.Monad.Apiary.Filter: root :: Monad n => ApiaryT c n m b -> ApiaryT c n m b
- Control.Monad.Apiary.Filter: ssl :: (Functor n, Monad n) => ApiaryT c n m a -> ApiaryT c n m a
+ Control.Monad.Apiary.Filter: ssl :: Monad n => ApiaryT c n m a -> ApiaryT c n m a
- Control.Monad.Apiary.Filter: stdMethod :: (Functor n, Monad n) => StdMethod -> ApiaryT c n m a -> ApiaryT c n m a
+ Control.Monad.Apiary.Filter: stdMethod :: Monad n => StdMethod -> ApiaryT c n m a -> ApiaryT c n m a
- Control.Monad.Apiary.Filter.Internal: focus :: (Functor n, Monad n) => (SList c -> ActionT n (SList c')) -> ApiaryT c' n m a -> ApiaryT c n m a
+ Control.Monad.Apiary.Filter.Internal: focus :: Monad n => (Doc -> Doc) -> (SList c -> ActionT n (SList c')) -> ApiaryT c' n m a -> ApiaryT c n m a
- Control.Monad.Apiary.Filter.Internal: function :: (Functor n, Monad n) => (SList c -> Request -> Maybe (SList c')) -> ApiaryT c' n m b -> ApiaryT c n m b
+ Control.Monad.Apiary.Filter.Internal: function :: Monad n => (Doc -> Doc) -> (SList c -> Request -> Maybe (SList c')) -> ApiaryT c' n m b -> ApiaryT c n m b
- Control.Monad.Apiary.Filter.Internal: function' :: (Functor n, Monad n) => (Request -> Maybe a) -> ApiaryT (Snoc as a) n m b -> ApiaryT as n m b
+ Control.Monad.Apiary.Filter.Internal: function' :: Monad n => (Doc -> Doc) -> (Request -> Maybe a) -> ApiaryT (Snoc as a) n m b -> ApiaryT as n m b
- Control.Monad.Apiary.Filter.Internal: function_ :: (Functor n, Monad n) => (Request -> Bool) -> ApiaryT c n m b -> ApiaryT c n m b
+ Control.Monad.Apiary.Filter.Internal: function_ :: Monad n => (Doc -> Doc) -> (Request -> Bool) -> ApiaryT c n m b -> ApiaryT c n m b
- Data.Apiary.Param: class Path a
+ Data.Apiary.Param: class Typeable a => Path a where pathRep = typeRep
- Data.Apiary.Param: class Query a
+ Data.Apiary.Param: class Typeable a => Query a where queryRep = Strict . typeRep
- Data.Apiary.Param: pFile :: Proxy (File ByteString)
+ Data.Apiary.Param: pFile :: Proxy File
- Data.Apiary.Param: reqParams :: ReqParam a => Proxy a -> Request -> [Param] -> [File ByteString] -> [(ByteString, Maybe a)]
+ Data.Apiary.Param: reqParams :: ReqParam a => proxy a -> Request -> [Param] -> [File] -> [(ByteString, Maybe a)]
Files
- apiary.cabal +35/−31
- src/Control/Monad/Apiary.hs +4/−0
- src/Control/Monad/Apiary/Action.hs +4/−2
- src/Control/Monad/Apiary/Action/Internal.hs +47/−26
- src/Control/Monad/Apiary/Filter.hs +54/−34
- src/Control/Monad/Apiary/Filter/Internal.hs +8/−8
- src/Control/Monad/Apiary/Filter/Internal/Capture.hs +19/−20
- src/Control/Monad/Apiary/Filter/Internal/Capture/TH.hs +13/−3
- src/Control/Monad/Apiary/Filter/Internal/Strategy.hs +31/−15
- src/Control/Monad/Apiary/Internal.hs +98/−54
- src/Data/Apiary/Document.hs +159/−0
- src/Data/Apiary/Param.hs +102/−47
- src/Web/Apiary.hs +1/−2
- src/Web/Apiary/TH.hs +0/−1
apiary.cabal view
@@ -1,8 +1,8 @@ name: apiary-version: 0.11.3-synopsis: Simple web framework inspired by scotty.+version: 0.12.0+synopsis: Simple and type safe web framework that can be automatically generate API document. description:- Simple web framework inspired by scotty.+ Simple and type safe web framework that can be automatically generate API document. . @ {-# LANGUAGE QuasiQuotes #-}@@ -35,6 +35,8 @@ . * type safe route filter. .+ * auto generate API documentation(https://github.com/philopon/apiary/blob/master/examples/api.hs>).+ . more examples: <https://github.com/philopon/apiary/blob/master/examples/> license: MIT@@ -66,6 +68,7 @@ Data.Apiary.SList Data.Apiary.Param+ Data.Apiary.Document other-modules: Control.Monad.Apiary.Internal Control.Monad.Apiary.Action.Internal@@ -80,33 +83,34 @@ , Rank2Types - build-depends: base >=4.6 && <4.8- , template-haskell >=2.8 && <2.10- , mtl >=2.1 && <2.3- , monad-control >=0.3 && <0.4- , transformers-base >=0.4 && <0.5+ build-depends: base >=4.6 && <4.8+ , template-haskell >=2.8 && <2.10+ , mtl >=2.1 && <2.3+ , monad-control >=0.3 && <0.4+ , transformers-base >=0.4 && <0.5 - , text >=1.1 && <1.2- , bytestring >=0.10 && <0.11- , blaze-builder >=0.3 && <0.4- , data-default-class >=0.0 && <0.1- , reflection >=1.4 && <1.5+ , text >=1.1 && <1.2+ , bytestring >=0.10 && <0.11+ , blaze-builder >=0.3 && <0.4+ , data-default-class >=0.0 && <0.1+ , reflection >=1.4 && <1.5 - , http-types >=0.8 && <0.9- , mime-types >=0.1 && <0.2- , exceptions >=0.6 && <0.7+ , http-types >=0.8 && <0.9+ , mime-types >=0.1 && <0.2+ , exceptions >=0.6 && <0.7+ , blaze-html >=0.7 && <0.8 if impl(ghc < 7.8)- build-depends: tagged >=0.7 && <0.8+ build-depends: tagged >=0.7 && <0.8 if flag(wai3)- build-depends: wai >=3.0 && <3.1- , wai-extra >=3.0 && <3.1+ build-depends: wai >=3.0 && <3.1+ , wai-extra >=3.0 && <3.1 cpp-options: -DWAI3 else- build-depends: wai >=2.1 && <2.2- , wai-extra >=2.1 && <2.2- , conduit >=1.1 && <1.2+ build-depends: wai >=2.1 && <2.2+ , wai-extra >=2.1 && <2.2+ , conduit >=1.1 && <1.2 hs-source-dirs: src ghc-options: -O2 -Wall@@ -115,18 +119,18 @@ test-suite test-framework main-is: main.hs type: exitcode-stdio-1.0- build-depends: base >=4.6 && <4.8- , test-framework >=0.8 && <0.9- , test-framework-hunit >=0.3 && <0.4+ build-depends: base >=4.6 && <4.8+ , test-framework >=0.8 && <0.9+ , test-framework-hunit >=0.3 && <0.4 , apiary- , bytestring >=0.10 && <0.11- , http-types >=0.8 && <0.9+ , bytestring >=0.10 && <0.11+ , http-types >=0.8 && <0.9 if flag(wai3)- build-depends: wai >=3.0 && <3.1- , wai-extra >=3.0 && <3.1+ build-depends: wai >=3.0 && <3.1+ , wai-extra >=3.0 && <3.1 else- build-depends: wai >=2.1 && <2.2- , wai-test >=2.0 && <2.1+ build-depends: wai >=2.1 && <2.2+ , wai-test >=2.0 && <2.1 hs-source-dirs: test ghc-options: -O2 -Wall -fno-warn-missing-signatures
src/Control/Monad/Apiary.hs view
@@ -2,10 +2,14 @@ ( ApiaryT, Apiary , runApiary , runApiaryT+ , runApiaryT' -- * getter , apiaryConfig -- * execute action , action, action'+ -- * API documentation+ , group+ , document -- * deprecated , actionWithPreAction ) where
src/Control/Monad/Apiary/Action.hs view
@@ -1,8 +1,7 @@ {-# LANGUAGE CPP #-} module Control.Monad.Apiary.Action - (- ActionT+ ( ActionT , ApiaryConfig(..) -- * actions , stop, stopWith@@ -17,8 +16,10 @@ , status -- *** response header , addHeader, setHeaders, modifyHeader+ , ContentType , contentType -- *** response body+ , File(..) , file , file' , builder@@ -42,6 +43,7 @@ import Control.Monad.Apiary.Action.Internal import Data.Default.Class+import Data.Apiary.Param import Network.HTTP.Types.Status hiding (mkStatus) #ifdef WAI3
src/Control/Monad/Apiary/Action/Internal.hs view
@@ -8,6 +8,8 @@ {-# LANGUAGE NoMonomorphismRestriction #-} {-# LANGUAGE CPP #-} {-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE TupleSections #-} module Control.Monad.Apiary.Action.Internal where @@ -18,12 +20,17 @@ import Control.Monad.Reader import Control.Monad.Catch import Control.Monad.Trans.Control+ import Network.Wai-import Network.Wai.Parse+import qualified Network.Wai.Parse as P import Network.Mime-import Data.Default.Class import Network.HTTP.Types++import Data.Apiary.Param+import Data.Apiary.Document+import Data.Default.Class import Blaze.ByteString.Builder+import Text.Blaze.Html.Renderer.Utf8 import qualified Data.ByteString as S import qualified Data.ByteString.Lazy as L import qualified Data.Text as T@@ -34,41 +41,52 @@ data ApiaryConfig = ApiaryConfig { -- | call when no handler matched.- notFound :: Application+ notFound :: Application -- | used unless call 'status' function.- , defaultStatus :: Status+ , defaultStatus :: Status -- | initial headers.- , defaultHeader :: ResponseHeaders+ , defaultHeader :: ResponseHeaders -- | used by 'Control.Monad.Apiary.Filter.root' filter.- , rootPattern :: [S.ByteString]- , mimeType :: FilePath -> S.ByteString+ , rootPattern :: [S.ByteString]+ , mimeType :: FilePath -> S.ByteString+ , documentAction :: Documents -> ActionT IO () } +defaultDocument :: Monad m => S.ByteString -> Documents -> ActionT m ()+defaultDocument r d = do+ p <- rawPathInfo <$> getRequest+ guard $ p == r+ contentType "text/html"+ builder . renderHtmlBuilder $ defaultDocumentToHtml d+ defNotFound :: Application #ifdef WAI3-defNotFound _ f = f $ responseLBS status404 [("Content-Type", "text/plain")] "404 Page Notfound.\n"+defNotFound _ f = f $ responseLBS status404 [("Content-Type", "text/plain")] "404 Page Notfound.\n" #else-defNotFound _ = return $ responseLBS status404 [("Content-Type", "text/plain")] "404 Page Notfound.\n"+defNotFound _ = return $ responseLBS status404 [("Content-Type", "text/plain")] "404 Page Notfound.\n" #endif instance Default ApiaryConfig where def = ApiaryConfig - { notFound = defNotFound- , defaultStatus = ok200- , defaultHeader = []- , rootPattern = ["", "/", "/index.html", "/index.htm"]- , mimeType = defaultMimeLookup . T.pack+ { notFound = defNotFound+ , defaultStatus = ok200+ , defaultHeader = []+ , rootPattern = ["", "/", "/index.html", "/index.htm"]+ , mimeType = defaultMimeLookup . T.pack+ , documentAction = defaultDocument "/api/document" } -data ActionState - = ActionState- { actionResponse :: Response- , actionStatus :: Status- , actionHeaders :: ResponseHeaders- , actionReqBody :: Maybe ([Param], [File L.ByteString])- , actionPathInfo :: [T.Text]- }+convFile :: (S.ByteString, P.FileInfo L.ByteString) -> File+convFile (p, P.FileInfo{..}) = File p fileName fileContentType fileContent +data ActionState = ActionState+ { actionResponse :: Response+ , actionStatus :: Status+ , actionHeaders :: ResponseHeaders+ , actionReqBody :: Maybe ([Param], [File])+ , actionPathInfo :: [T.Text]+ }+ initialState :: ApiaryConfig -> Request -> ActionState initialState conf req = ActionState { actionResponse = responseLBS (defaultStatus conf) (defaultHeader conf) ""@@ -217,11 +235,12 @@ getRequest :: Monad m => ActionT m Request getRequest = ActionT $ \_ r s c -> c r s -getRequestBody :: MonadIO m => ActionT m ([Param], [File L.ByteString])+getRequestBody :: MonadIO m => ActionT m ([Param], [File]) getRequestBody = ActionT $ \_ r s c -> case actionReqBody s of Just b -> c b s Nothing -> do- b <- liftIO $ parseRequestBody lbsBackEnd r+ (p,f) <- liftIO $ P.parseRequestBody P.lbsBackEnd r+ let b = (p, map convFile f) c b s { actionReqBody = Just b } -- | parse request body and return params. since 0.9.0.0.@@ -229,7 +248,7 @@ getReqParams = fst <$> getRequestBody -- | parse request body and return files. since 0.9.0.0.-getReqFiles :: MonadIO m => ActionT m [File L.ByteString]+getReqFiles :: MonadIO m => ActionT m [File] getReqFiles = snd <$> getRequestBody getConfig :: Monad m => ActionT m ApiaryConfig@@ -261,9 +280,11 @@ setHeaders :: Monad m => ResponseHeaders -> ActionT m () setHeaders hs = modifyHeader (const hs) +type ContentType = S.ByteString+ -- | set content-type header. -- if content-type header already exists, replace it. since 0.1.0.0.-contentType :: Monad m => S.ByteString -> ActionT m ()+contentType :: Monad m => ContentType -> ActionT m () contentType c = modifyHeader (\h -> ("Content-Type", c) : filter (("Content-Type" /=) . fst) h)
src/Control/Monad/Apiary/Filter.hs view
@@ -6,6 +6,7 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE RecordWildCards #-} module Control.Monad.Apiary.Filter ( -- * filters@@ -22,6 +23,7 @@ , Capture.fetch -- ** query matcher+ , QueryKey(..) , query -- *** specified operators , (=:), (=!:), (=?:), (?:), (=*:), (=+:)@@ -51,11 +53,15 @@ import qualified Network.HTTP.Types as HT import Network.HTTP.Types (StdMethod(..)) import qualified Data.ByteString as S+import qualified Data.ByteString.Char8 as SC import Data.Proxy+import Data.String import Data.Reflection+import Text.Blaze.Html import Data.Apiary.SList import Data.Apiary.Param+import Data.Apiary.Document import Control.Monad.Apiary.Action.Internal import Control.Monad.Apiary.Filter.Internal@@ -66,40 +72,49 @@ import Control.Monad.Apiary.Internal -- | filter by HTTP method. since 0.1.0.0.-method :: (Functor n, Monad n) => HT.Method -> ApiaryT c n m a -> ApiaryT c n m a-method m = function_ ((m ==) . requestMethod)+method :: Monad n => HT.Method -> ApiaryT c n m a -> ApiaryT c n m a+method m = function_ (DocMethod m) ((m ==) . requestMethod) -- | filter by HTTP method using StdMethod. since 0.1.0.0.-stdMethod :: (Functor n, Monad n) => StdMethod -> ApiaryT c n m a -> ApiaryT c n m a+stdMethod :: Monad n => StdMethod -> ApiaryT c n m a -> ApiaryT c n m a stdMethod = method . HT.renderStdMethod -- | filter by ssl accessed. since 0.1.0.0.-ssl :: (Functor n, Monad n) => ApiaryT c n m a -> ApiaryT c n m a-ssl = function_ isSecure+ssl :: Monad n => ApiaryT c n m a -> ApiaryT c n m a+ssl = function_ id isSecure -- | http version filter. since 0.5.0.0.-httpVersion :: (Functor n, Monad n) => HT.HttpVersion- -> ApiaryT c n m b -> ApiaryT c n m b-httpVersion v = function_ $ (v ==) . Wai.httpVersion+httpVersion :: Monad n => HT.HttpVersion -> ApiaryT c n m b -> ApiaryT c n m b+httpVersion v = function_ id $ (v ==) . Wai.httpVersion -- | http/0.9 only accepted fiter. since 0.5.0.0.-http09 :: (Functor n, Monad n) => ApiaryT c n m b -> ApiaryT c n m b+http09 :: Monad n => ApiaryT c n m b -> ApiaryT c n m b http09 = Control.Monad.Apiary.Filter.httpVersion HT.http09 -- | http/1.0 only accepted fiter. since 0.5.0.0.-http10 :: (Functor n, Monad n) => ApiaryT c n m b -> ApiaryT c n m b+http10 :: Monad n => ApiaryT c n m b -> ApiaryT c n m b http10 = Control.Monad.Apiary.Filter.httpVersion HT.http10 -- | http/1.1 only accepted fiter. since 0.5.0.0.-http11 :: (Functor n, Monad n) => ApiaryT c n m b -> ApiaryT c n m b+http11 :: Monad n => ApiaryT c n m b -> ApiaryT c n m b http11 = Control.Monad.Apiary.Filter.httpVersion HT.http11 -- | filter by 'Control.Monad.Apiary.Action.rootPattern' of 'Control.Monad.Apiary.Action.ApiaryConfig'.-root :: (Functor n, Monad n) => ApiaryT c n m b -> ApiaryT c n m b+root :: Monad n => ApiaryT c n m b -> ApiaryT c n m b root m = do rs <- rootPattern `liftM` apiaryConfig- function_ (\r -> rawPathInfo r `elem` rs) m+ function_ DocRoot (\r -> rawPathInfo r `elem` rs) m +data QueryKey = QueryKey+ { queryKey :: S.ByteString+ , queryDesc :: Maybe Html+ }++instance IsString QueryKey where+ fromString s = case break (== ':') s of+ (k, []) -> QueryKey (SC.pack k) Nothing+ (k, d) -> QueryKey (SC.pack k) (Just . toHtml $ tail d)+ -- | low level query getter. since 0.5.0.0. -- -- @@@ -114,25 +129,30 @@ -- query "key" (Proxy :: Proxy ('Many' String) -- get all \'key\' query parameter as String. -- @ query :: forall a as w n m b proxy. - (ReqParam a, Strategy.Strategy w, Functor n, MonadIO n)- => S.ByteString+ (ReqParam a, Strategy.Strategy w, MonadIO n)+ => QueryKey -> proxy (w a) -> ApiaryT (Strategy.SNext w as a) n m b -> ApiaryT as n m b-query key p = focus $ \l -> do- r <- getRequest- (q,f) <- getRequestBody+query QueryKey{..} p =+ focus doc $ \l -> do+ r <- getRequest+ (q,f) <- getRequestBody - maybe mzero return $- Strategy.readStrategy id ((key ==) . fst) p - (reqParams (Proxy :: Proxy a) r q f) l+ maybe mzero return $+ Strategy.readStrategy id ((queryKey ==) . fst) p + (reqParams (Proxy :: Proxy a) r q f) l+ where+ doc = case queryDesc of+ Nothing -> id+ Just h -> DocQuery queryKey (Strategy.strategyRep (Proxy :: Proxy w)) (reqParamRep (Proxy :: Proxy a)) h -- | get first matched paramerer. since 0.5.0.0. -- -- @ -- "key" =: pInt == query "key" (pFirst pInt) == query "key" (Proxy :: Proxy (First Int)) -- @-(=:) :: (Functor n, MonadIO n, ReqParam a) => S.ByteString -> proxy a +(=:) :: (MonadIO n, ReqParam a) => QueryKey -> proxy a -> ApiaryT (Snoc as a) n m b -> ApiaryT as n m b k =: t = query k (pFirst t) @@ -143,7 +163,7 @@ -- @ -- "key" =: pInt == query "key" (pOne pInt) == query "key" (Proxy :: Proxy (One Int)) -- @-(=!:) :: (Functor n, MonadIO n, ReqParam a) => S.ByteString -> proxy a +(=!:) :: (MonadIO n, ReqParam a) => QueryKey -> proxy a -> ApiaryT (Snoc as a) n m b -> ApiaryT as n m b k =!: t = query k (pOne t) @@ -154,7 +174,7 @@ -- @ -- "key" =: pInt == query "key" (pOption pInt) == query "key" (Proxy :: Proxy (Option Int)) -- @-(=?:) :: (Functor n, MonadIO n, ReqParam a) => S.ByteString -> proxy a +(=?:) :: (MonadIO n, ReqParam a) => QueryKey -> proxy a -> ApiaryT (Snoc as (Maybe a)) n m b -> ApiaryT as n m b k =?: t = query k (pOption t) @@ -165,7 +185,7 @@ -- @ -- "key" =: pInt == query "key" (pCheck pInt) == query "key" (Proxy :: Proxy (Check Int)) -- @-(?:) :: (Functor n, MonadIO n, ReqParam a) => S.ByteString -> proxy a +(?:) :: (MonadIO n, ReqParam a) => QueryKey -> proxy a -> ApiaryT as n m b -> ApiaryT as n m b k ?: t = query k (pCheck t) @@ -174,7 +194,7 @@ -- @ -- "key" =: pInt == query "key" (pMany pInt) == query "key" (Proxy :: Proxy (Many Int)) -- @-(=*:) :: (Functor n, MonadIO n, ReqParam a) => S.ByteString -> proxy a +(=*:) :: (MonadIO n, ReqParam a) => QueryKey -> proxy a -> ApiaryT (Snoc as [a]) n m b -> ApiaryT as n m b k =*: t = query k (pMany t) @@ -183,7 +203,7 @@ -- @ -- "key" =: pInt == query "key" (pSome pInt) == query "key" (Proxy :: Proxy (Some Int)) -- @-(=+:) :: (Functor n, MonadIO n, ReqParam a) => S.ByteString -> proxy a +(=+:) :: (MonadIO n, ReqParam a) => QueryKey -> proxy a -> ApiaryT (Snoc as [a]) n m b -> ApiaryT as n m b k =+: t = query k (pSome t) @@ -193,17 +213,17 @@ -- hasQuery q = 'query' q (Proxy :: Proxy ('Check' ())) -- @ ---hasQuery :: (Functor n, MonadIO n) => S.ByteString -> ApiaryT c n m a -> ApiaryT c n m a+hasQuery :: (MonadIO n) => QueryKey -> ApiaryT c n m a -> ApiaryT c n m a hasQuery q = query q (Proxy :: Proxy (Strategy.Check ())) -------------------------------------------------------------------------------- -- | check whether to exists specified header or not. since 0.6.0.0.-hasHeader :: (Functor n, Monad n) => HT.HeaderName -> ApiaryT as n m b -> ApiaryT as n m b+hasHeader :: Monad n => HT.HeaderName -> ApiaryT as n m b -> ApiaryT as n m b hasHeader n = header' pCheck ((n ==) . fst) -- | check whether to exists specified valued header or not. since 0.6.0.0.-eqHeader :: (Functor n, Monad n)+eqHeader :: Monad n => HT.HeaderName -> S.ByteString -- ^ header value -> ApiaryT as n m b@@ -211,12 +231,12 @@ eqHeader k v = header' pCheck (\(k',v') -> k == k' && v == v') -- | filter by header and get first. since 0.6.0.0.-header :: (Functor n, Monad n) => HT.HeaderName+header :: Monad n => HT.HeaderName -> ApiaryT (Snoc as S.ByteString) n m b -> ApiaryT as n m b header n = header' pFirst ((n ==) . fst) -- | filter by headers up to 100 entries. since 0.6.0.0.-headers :: (Functor n, Monad n) => HT.HeaderName+headers :: Monad n => HT.HeaderName -> ApiaryT (Snoc as [S.ByteString]) n m b -> ApiaryT as n m b headers n = header' limit100 ((n ==) . fst) where@@ -224,10 +244,10 @@ limit100 _ = Proxy -- | low level header filter. since 0.6.0.0.-header' :: (Strategy.Strategy w, Functor n, Monad n)+header' :: (Strategy.Strategy w, Monad n) => (forall x. Proxy x -> Proxy (w x)) -> (HT.Header -> Bool) -> ApiaryT (Strategy.SNext w as S.ByteString) n m b -> ApiaryT as n m b-header' pf kf = function $ \l r ->+header' pf kf = function id $ \l r -> Strategy.readStrategy Just kf (pf pByteString) (requestHeaders r) l
src/Control/Monad/Apiary/Filter/Internal.hs view
@@ -7,22 +7,22 @@ import Control.Monad.Apiary.Action import Network.Wai import Data.Apiary.SList+import Data.Apiary.Document -- | low level filter function.-function :: (Functor n, Monad n) => (SList c -> Request -> Maybe (SList c'))+function :: Monad n => (Doc -> Doc)+ -> (SList c -> Request -> Maybe (SList c')) -> ApiaryT c' n m b -> ApiaryT c n m b-function f = focus $ \c -> getRequest >>= \r -> case f c r of+function d f = focus d $ \c -> getRequest >>= \r -> case f c r of Nothing -> mzero Just c' -> return c' -- | filter and append argument.-function' :: (Functor n, Monad n) => (Request -> Maybe a)+function' :: Monad n => (Doc -> Doc) -> (Request -> Maybe a) -> ApiaryT (Snoc as a) n m b -> ApiaryT as n m b-function' f = function $ \c r -> sSnoc c `fmap` f r+function' d f = function d $ \c r -> sSnoc c `fmap` f r -- | filter only(not modify arguments).-function_ :: (Functor n, Monad n) => (Request -> Bool) +function_ :: Monad n => (Doc -> Doc) -> (Request -> Bool) -> ApiaryT c n m b -> ApiaryT c n m b-function_ f = function $ \c r -> if f r then Just c else Nothing--+function_ d f = function d $ \c r -> if f r then Just c else Nothing
src/Control/Monad/Apiary/Filter/Internal/Capture.hs view
@@ -16,37 +16,36 @@ import Control.Applicative import Control.Monad import qualified Data.Text as T+import Text.Blaze.Html+ import Data.Apiary.Param import Data.Apiary.SList+import Data.Apiary.Document import Control.Monad.Apiary.Action.Internal-import Control.Monad.Apiary-import Control.Monad.Apiary.Filter.Internal+import Control.Monad.Apiary.Internal --- | check first path and drill down. since v0.11.0.-path :: (Functor n, Monad n) - => T.Text -> ApiaryT c n m a -> ApiaryT c n m a-path p = focus $ \l -> l <$ path'+-- | check first path and drill down. since 0.11.0.+path :: Monad n => T.Text -> ApiaryT c n m a -> ApiaryT c n m a+path p = focus (DocPath p) $ \l -> l <$ path' where path' = liftM actionPathInfo getState >>= \case c:_ | c == p -> modifyState (\s -> s {actionPathInfo = tail $ actionPathInfo s})- _ -> empty+ _ -> mzero --- | check consumed pathes. since v0.11.1.-endPath :: (Functor n, Monad n) => ApiaryT c n m a -> ApiaryT c n m a-endPath = focus $ \l -> l <$ end+-- | check consumed pathes. since 0.11.1.+endPath :: Monad n => ApiaryT c n m a -> ApiaryT c n m a+endPath = focus id $ \l -> l <$ end where end = liftM actionPathInfo getState >>= \case [] -> return ()- _ -> empty+ _ -> mzero --- | get first path and drill down. since v0.11.0.-fetch :: (Path a, Functor n, Monad n)- => proxy a -> ApiaryT (Snoc as a) n m b -> ApiaryT as n m b-fetch p = focus $ \l -> liftM actionPathInfo getState >>= \case- [] -> empty+-- | get first path and drill down. since 0.11.0.+fetch :: (Path a, Monad n) => proxy a -> Maybe Html -> ApiaryT (Snoc as a) n m b -> ApiaryT as n m b+fetch p h = focus (DocFetch (pathRep p) h) $ \l -> liftM actionPathInfo getState >>= \case+ [] -> mzero c:_ -> case readPathAs p c of- Nothing -> empty- Just r -> do- modifyState (\s -> s { actionPathInfo = tail $ actionPathInfo s})- return (sSnoc l r)+ Nothing -> mzero+ Just r -> sSnoc l r <$+ modifyState (\s -> s {actionPathInfo = tail $ actionPathInfo s})
src/Control/Monad/Apiary/Filter/Internal/Capture/TH.hs view
@@ -17,12 +17,22 @@ splitPath :: String -> [String] splitPath = map T.unpack . T.splitOn "/" . T.pack +description :: Monad m => String -> m (String, Maybe String)+description s = case break (== '(') s of+ (t, []) -> return (t, Nothing)+ (t, st) -> case break (== ')') st of+ (_:b, ")") -> return (t, Just b)+ (_, _) -> fail "capture: syntax error." + mkCap :: [String] -> ExpQ mkCap [] = [|Capture.endPath|] mkCap ((':':tyStr):as) = do- -- ty <- lookupTypeName tyStr >>= maybe (fail "") return- let ty = mkName tyStr- [|Capture.fetch (Proxy :: Proxy $(conT ty)) . $(mkCap as) |]+ (t, mbd) <- description tyStr+ ty <- lookupTypeName t >>= maybe (fail $ t ++ " not found.") return+ let d = case mbd of+ Nothing -> [|Nothing|]+ Just h -> [|Just $(stringE h)|]+ [|Capture.fetch (Proxy :: Proxy $(conT ty)) $d . $(mkCap as)|] mkCap (eq:as) = do [|(Capture.path $(stringE eq)) . $(mkCap as) |]
src/Control/Monad/Apiary/Filter/Internal/Strategy.hs view
@@ -3,32 +3,41 @@ {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE NoMonomorphismRestriction #-}+{-# LANGUAGE CPP #-} module Control.Monad.Apiary.Filter.Internal.Strategy where import Data.Apiary.SList+import qualified Data.Text as T+import Data.Apiary.Document +import Data.Typeable import Data.Maybe-import Data.Proxy import Data.Reflection+#if __GLASGOW_HASKELL__ < 707+import Data.Proxy+#endif class Strategy (w :: * -> *) where- type SNext w (as :: [*]) a :: [*]- readStrategy :: (v -> Maybe a)- -> ((k,v) -> Bool)- -> proxy (w a)- -> [(k, v)]- -> SList as - -> Maybe (SList (SNext w as a))+ type SNext w (as :: [*]) a :: [*]+ readStrategy :: (v -> Maybe a)+ -> ((k,v) -> Bool)+ -> proxy (w a)+ -> [(k, v)]+ -> SList as + -> Maybe (SList (SNext w as a))+ strategyRep :: proxy w -> StrategyRep getQuery :: (v -> Maybe a) -> proxy (w a) -> ((k,v) -> Bool) -> [(k, v)] -> [Maybe a] getQuery readf _ kf = map readf . map snd . filter kf -- | get first matched key( [1,) params to Type.). since 0.5.0.0.-data Option a+data Option a deriving Typeable instance Strategy Option where type SNext Option as a = Snoc as (Maybe a) readStrategy rf k p q l =@@ -38,9 +47,10 @@ else Just . sSnoc l $ case catMaybes rs of [] -> Nothing a:_ -> Just a+ strategyRep _ = StrategyRep "optional" -- | get first matched key ( [0,) params to Maybe Type.) since 0.5.0.0.-data First a+data First a deriving Typeable instance Strategy First where type SNext First as a = Snoc as a readStrategy rf k p q l =@@ -50,9 +60,10 @@ else case catMaybes rs of [] -> Nothing a:_ -> Just $ sSnoc l a+ strategyRep _ = StrategyRep "first" -- | get key ( [1] param to Type.) since 0.5.0.0.-data One a+data One a deriving Typeable instance Strategy One where type SNext One as a = Snoc as a readStrategy rf k p q l =@@ -62,9 +73,10 @@ else case catMaybes rs of [a] -> Just $ sSnoc l a _ -> Nothing+ strategyRep _ = StrategyRep "one" -- | get parameters ( [0,) params to [Type] ) since 0.5.0.0.-data Many a+data Many a deriving Typeable instance Strategy Many where type SNext Many as a = Snoc as [a] readStrategy rf k p q l =@@ -72,9 +84,10 @@ in if any isNothing rs then Nothing else Just $ sSnoc l (catMaybes rs)+ strategyRep _ = StrategyRep "many" -- | get parameters ( [1,) params to [Type] ) since 0.5.0.0.-data Some a+data Some a deriving Typeable instance Strategy Some where type SNext Some as a = Snoc as [a] readStrategy rf k p q l =@@ -84,9 +97,10 @@ else case catMaybes rs of [] -> Nothing as -> Just $ sSnoc l as+ strategyRep _ = StrategyRep "some" -- | get parameters with upper limit ( [1,n] to [Type]) since 0.6.0.0.-data LimitSome u a+data LimitSome u a deriving Typeable instance (Reifies u Int) => Strategy (LimitSome u) where type SNext (LimitSome u) as a = Snoc as [a] readStrategy rf k p q l =@@ -96,6 +110,7 @@ else case catMaybes rs of [] -> Nothing as -> Just $ sSnoc l as+ strategyRep _ = StrategyRep . T.pack $ "less then " ++ show (reflect (Proxy :: Proxy u)) reflectLimit :: Reifies n Int => proxy (LimitSome n a) -> Int reflectLimit p = reflect $ asTyInt p@@ -104,7 +119,7 @@ asTyInt _ = Proxy -- | type check ( [0,) params to No argument ) since 0.5.0.0.-data Check a+data Check a deriving Typeable instance Strategy Check where type SNext Check as a = as readStrategy rf k p q l =@@ -114,6 +129,7 @@ else case catMaybes rs of [] -> Nothing _ -> Just l+ strategyRep _ = StrategyRep "check" -- | construct Option proxy. since 0.5.1.0. pOption :: proxy a -> Proxy (Option a)
src/Control/Monad/Apiary/Internal.hs view
@@ -5,6 +5,7 @@ {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE KindSignatures #-}@@ -22,14 +23,35 @@ import Control.Monad.Trans.Control import Control.Monad.Base import Data.Apiary.SList+import Data.Apiary.Document+import Data.Monoid+import qualified Data.Text as T import Control.Monad.Apiary.Action.Internal +data ApiaryReader n c = ApiaryReader+ { readerFilter :: ActionT n (SList c)+ , readerConfig :: ApiaryConfig+ , readerDoc :: Doc -> Doc+ }++data ApiaryWriter n = ApiaryWriter+ { writerHandler :: ActionT n ()+ , writerDoc :: [Doc]+ }++instance Monad n => Monoid (ApiaryWriter n) where+ mempty = ApiaryWriter mzero []+ ApiaryWriter ah ad `mappend` ApiaryWriter bh bd =+ ApiaryWriter (mplus ah bh) (ad <> bd)++initialReader :: Monad n => ApiaryConfig -> ApiaryReader n '[]+initialReader conf = ApiaryReader (return SNil) conf id+ -- | most generic Apiary monad. since 0.8.0.0. newtype ApiaryT c n m a = ApiaryT { unApiaryT :: forall b.- ActionT n (SList c)- -> ApiaryConfig- -> (a -> ActionT n () -> m b)+ ApiaryReader n c+ -> (a -> ApiaryWriter n -> m b) -> m b } @@ -37,89 +59,111 @@ type Apiary c = ApiaryT c IO Identity instance Functor (ApiaryT c n m) where- fmap f m = ApiaryT $ \grd conf cont ->- unApiaryT m grd conf $ \a hdr -> hdr `seq` cont (f a) hdr+ fmap f m = ApiaryT $ \rdr cont ->+ unApiaryT m rdr $ \a hdr -> hdr `seq` cont (f a) hdr -instance (Monad n, Functor n) => Applicative (ApiaryT c n m) where- pure x = ApiaryT $ \_ _ cont -> cont x empty- mf <*> ma = ApiaryT $ \grd conf cont ->- unApiaryT mf grd conf $ \f hdr ->- unApiaryT ma grd conf $ \a hdr' ->- let hdr'' = hdr <|> hdr'+instance Monad n => Applicative (ApiaryT c n m) where+ pure x = ApiaryT $ \_ cont -> cont x mempty+ mf <*> ma = ApiaryT $ \rdr cont ->+ unApiaryT mf rdr $ \f hdr ->+ unApiaryT ma rdr $ \a hdr' ->+ let hdr'' = hdr <> hdr' in hdr'' `seq` cont (f a) hdr'' -instance (Monad n, Functor n) => Monad (ApiaryT c n m) where- return x = ApiaryT $ \_ _ cont -> cont x empty- m >>= k = ApiaryT $ \grd conf cont ->- unApiaryT m grd conf $ \a hdr ->- unApiaryT (k a) grd conf $ \b hdr' -> - let hdr'' = hdr <|> hdr'+instance Monad n => Monad (ApiaryT c n m) where+ return x = ApiaryT $ \_ cont -> cont x mempty+ m >>= k = ApiaryT $ \rdr cont ->+ unApiaryT m rdr $ \a hdr ->+ unApiaryT (k a) rdr $ \b hdr' -> + let hdr'' = hdr <> hdr' in hdr'' `seq` cont b hdr'' -instance (Functor n, Monad n) => MonadTrans (ApiaryT c n) where- lift m = ApiaryT $ \_ _ c -> m >>= \a -> c a empty+instance Monad n => MonadTrans (ApiaryT c n) where+ lift m = ApiaryT $ \_ c -> m >>= \a -> c a mempty -instance (Functor n, Monad n, MonadIO m) => MonadIO (ApiaryT c n m) where- liftIO m = ApiaryT $ \_ _ c -> liftIO m >>= \a -> c a empty+instance (Monad n, MonadIO m) => MonadIO (ApiaryT c n m) where+ liftIO m = ApiaryT $ \_ c -> liftIO m >>= \a -> c a mempty -instance (Functor n, Monad n, MonadBase b m) => MonadBase b (ApiaryT c n m) where- liftBase m = ApiaryT $ \_ _ c -> liftBase m >>= \a -> c a empty+instance (Monad n, MonadBase b m) => MonadBase b (ApiaryT c n m) where+ liftBase m = ApiaryT $ \_ c -> liftBase m >>= \a -> c a mempty apiaryT :: Monad m- => (ActionT n (SList c) -> ApiaryConfig -> m (a, ActionT n ()))+ => (ApiaryReader n c -> m (a, ApiaryWriter n)) -> ApiaryT c n m a-apiaryT f = ApiaryT $ \grd conf cont -> f grd conf >>= \(a,w) -> cont a w+apiaryT f = ApiaryT $ \rdr cont -> f rdr >>= \(a,w) -> cont a w -instance (Functor n, Monad n) => MonadTransControl (ApiaryT c n) where- newtype StT (ApiaryT c n) a = StTApiary' { unStTApiary' :: (a, ActionT n ()) }- liftWith f = apiaryT $ \g c ->- liftM (\a -> (a, empty)) - (f $ \t -> liftM StTApiary' $ unApiaryT t g c (\a w -> return (a,w)))- restoreT m = apiaryT $ \_ _ -> liftM unStTApiary' m+instance Monad n => MonadTransControl (ApiaryT c n) where+ newtype StT (ApiaryT c n) a = StTApiary' { unStTApiary' :: (a, ApiaryWriter n) }+ liftWith f = apiaryT $ \rdr ->+ liftM (\a -> (a, mempty)) + (f $ \t -> liftM StTApiary' $ unApiaryT t rdr (\a w -> return (a,w)))+ restoreT m = apiaryT $ \_ -> liftM unStTApiary' m -instance (Functor n, Monad n, MonadBaseControl b m) => MonadBaseControl b (ApiaryT c n m) where+instance (Monad n, MonadBaseControl b m) => MonadBaseControl b (ApiaryT c n m) where newtype StM (ApiaryT c n m) a = StMApiary' { unStMApiary' :: ComposeSt (ApiaryT c n) m a } liftBaseWith = defaultLiftBaseWith StMApiary' restoreM = defaultRestoreM unStMApiary' +runApiaryT' :: (Monad n, Monad m) => (forall b. n b -> IO b) -> ApiaryConfig+ -> ApiaryT '[] n m a -> m (Application, Documents)+runApiaryT' run conf m = unApiaryT m (initialReader conf) (\_ w -> return w) >>= \wtr -> do+ let doc = docsToDocuments $ writerDoc wtr+ app = execActionT conf $ hoistActionT run (writerHandler wtr) `mplus` documentAction conf doc+ return (app, doc)+ runApiaryT :: (Monad n, Monad m) => (forall b. n b -> IO b) -> ApiaryConfig- -> ApiaryT '[] n m a -> m Application-runApiaryT run conf m = unApiaryT m (return SNil) conf (\_ w -> return w) >>= \act ->- return $ execActionT conf (hoistActionT run act)+ -> ApiaryT '[] n m a -> m Application+runApiaryT run conf m = fst `liftM` runApiaryT' run conf m runApiary :: ApiaryConfig -> Apiary '[] a -> Application runApiary conf m = runIdentity $ runApiaryT id conf m -class MonadApiary c' m where- foa :: (SList c -> ActionT n (SList c')) -> m a -> m a--getGuard :: (Functor n, Monad n) => ApiaryT c n m (ActionT n (SList c))-getGuard = ApiaryT $ \grd _ c -> c grd empty--apiaryConfig :: (Functor n, Monad n) => ApiaryT c n m ApiaryConfig-apiaryConfig = ApiaryT $ \_ c cont -> cont c empty+apiaryConfig :: Monad n => ApiaryT c n m ApiaryConfig+apiaryConfig = ApiaryT $ \r cont -> cont (readerConfig r) mempty -addRoute :: (Functor n, Monad n) => ActionT n () -> ApiaryT c n m ()-addRoute r = ApiaryT $ \_ _ cont -> cont () r+addRoute :: Monad n => ApiaryWriter n -> ApiaryT c n m ()+addRoute r = ApiaryT $ \_ cont -> cont () r -- | filter by action. since 0.6.1.0.-focus :: (Functor n, Monad n) => (SList c -> ActionT n (SList c'))+focus :: Monad n => (Doc -> Doc) -> (SList c -> ActionT n (SList c')) -> ApiaryT c' n m a -> ApiaryT c n m a-focus g m = ApiaryT $ \grd cfg cont -> unApiaryT m (grd >>= g) cfg cont+focus d g m = ApiaryT $ \rdr cont -> unApiaryT m rdr + { readerFilter = readerFilter rdr >>= g + , readerDoc = readerDoc rdr . d+ } cont -- | splice ActionT ApiaryT.-action :: (Functor n, Monad n) => Fn c (ActionT n ()) -> ApiaryT c n m ()-action a = action' $ apply a+action :: Monad n => Fn c (ActionT n ()) -> ApiaryT c n m ()+action = action' . apply +-- | API document group. since 0.12.0.0.+--+-- only top level group recognized.+group :: T.Text -> ApiaryT c n m a -> ApiaryT c n m a+group d m = ApiaryT $ \rdr cont -> unApiaryT m rdr+ { readerDoc = readerDoc rdr . DocGroup d } cont++-- | add API document. since 0.12.0.0.+--+-- It use only filters prior document,+-- so you should be placed document directly in front of action.+document :: T.Text -> ApiaryT c n m a -> ApiaryT c n m a+document d m = ApiaryT $ \rdr cont -> unApiaryT m rdr+ { readerDoc = \_ -> readerDoc rdr (Document $ Just d) } cont+ {-# DEPRECATED actionWithPreAction "use action'" #-}--- | execute action before main action. since v0.4.2.0-actionWithPreAction :: (Functor n, Monad n) => (SList xs -> ActionT n a)+-- | execute action before main action. since 0.4.2.0+actionWithPreAction :: Monad n => (SList xs -> ActionT n a) -> Fn xs (ActionT n ()) -> ApiaryT xs n m () actionWithPreAction pa a = do action' $ \c -> pa c >> apply a c +getReader :: Monad n => ApiaryT c n m (ApiaryReader n c)+getReader = ApiaryT $ \rdr cont -> cont rdr mempty+ -- | like action. but not apply arguments. since 0.8.0.0.-action' :: (Functor n, Monad n) => (SList c -> ActionT n ()) -> ApiaryT c n m ()+action' :: Monad n => (SList c -> ActionT n ()) -> ApiaryT c n m () action' a = do- grd <- getGuard- addRoute $ grd >>= \c -> a c+ rdr <- getReader+ addRoute $ ApiaryWriter (readerFilter rdr >>= \c -> a c) + [readerDoc rdr $ Document Nothing]
+ src/Data/Apiary/Document.hs view
@@ -0,0 +1,159 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE NoMonomorphismRestriction #-}++module Data.Apiary.Document where++import Control.Applicative+import qualified Data.Text as T+import qualified Data.Text.Encoding as T+import qualified Data.ByteString as S+import Data.Typeable+import Data.Maybe+import Data.Apiary.Param+import qualified Network.HTTP.Types as HT+import Text.Blaze.Html+import qualified Text.Blaze.Html5 as H+import qualified Text.Blaze.Html5.Attributes as A+import Data.Monoid+import Data.List+import Data.Function++data StrategyRep = StrategyRep+ { strategyInfo :: T.Text }+ deriving (Show, Eq)++data Doc+ = DocPath T.Text Doc+ | DocRoot Doc+ | DocFetch TypeRep (Maybe Html) Doc+ | DocMethod HT.Method Doc+ | DocQuery S.ByteString StrategyRep QueryRep Html Doc+ | DocGroup T.Text Doc+ | Document (Maybe T.Text)++data Route+ = Path T.Text Route+ | Fetch TypeRep (Maybe Html) Route+ | End++instance Eq Route where+ Path a d == Path b d' = a == b && d == d'+ Fetch a _ d == Fetch b _ d' = a == b && d == d'+ End == End = True+ _ == _ = False++data Documents = Documents+ { noGroup :: [PathDoc]+ , groups :: [(T.Text, [PathDoc])]+ }++data PathDoc = PathDoc+ { path :: Route+ , methods :: [(HT.Method, MethodDoc)]+ }++data QueryDoc = QueryDoc+ { queryName :: S.ByteString+ , queryStrategy :: StrategyRep+ , queryRep :: QueryRep+ , queryDocument :: Html+ }++data MethodDoc = MethodDoc+ { queries :: [QueryDoc]+ , document :: T.Text+ }++docToDocument :: Doc -> Maybe (Maybe T.Text, PathDoc)+docToDocument = \case+ (DocGroup g d') -> (Just g,) <$> loop id (\md -> [("ANY", md)]) id d'+ d' -> (Nothing,) <$> loop id (\md -> [("ANY", md)]) id d'+ where+ loop ph mh qs (DocPath t d) = loop (ph . Path t) mh qs d+ loop _ mh qs (DocRoot d) = loop (const $ Path "" End) mh qs d+ loop ph mh qs (DocFetch t h d) = loop (ph . Fetch t h) mh qs d+ loop ph _ qs (DocMethod m d) = loop ph (\md -> [(m, md)]) qs d+ loop ph mh qs (DocQuery p s q t d) = loop ph mh (qs . (QueryDoc p s q t:)) d+ loop ph mh qs (DocGroup _ d) = loop ph mh qs d+ loop ph mh qs (Document (Just t)) = Just . PathDoc (ph End) $ mh (MethodDoc (qs []) t)+ loop _ _ _ (Document Nothing) = Nothing++mergeMethod :: [PathDoc] -> [PathDoc]+mergeMethod [] = []+mergeMethod (pd:pds) = merge pd (filter (same pd) pds) : mergeMethod (filter (not . same pd) pds)+ where+ same = (==) `on` path+ merge pd' pds' = PathDoc (path pd') (methods pd' ++ concatMap methods pds')++docsToDocuments :: [Doc] -> Documents+docsToDocuments doc =+ let gds = mapMaybe docToDocument doc+ ngs = mergeMethod . map snd $ filter ((Nothing ==) . fst) gds+ gs = map upGroup . groupBy ((==) `on` fst) $ mapMaybe trav gds+ in Documents ngs gs+ where+ upGroup ((g,d):ig) = (g, mergeMethod $ d : map snd ig)+ upGroup [] = error "docsToDocuments: unknown error."++ trav (Nothing, _) = Nothing+ trav (Just a, b) = Just (a, b)++routeToHtml :: Route -> (Html, Html)+routeToHtml = loop (1::Int) mempty []+ where+ sp = H.span "/" ! A.class_ "splitter"+ loop i r p (Path s d) = loop i (r <> sp <> H.span (toHtml s) ! A.class_ "path") p d+ loop i r p (Fetch t Nothing d) = + loop i (r <> sp <> H.span (toHtml $ ':' : show t) ! A.class_ "fetch") p d+ loop i r p (Fetch t (Just h) d) = + loop (succ i) (r <> sp <> H.span (toHtml (':' : show t) <> H.sup (toHtml i)) ! A.class_ "fetch")+ (p <> [H.tr $ H.td (toHtml i) <> H.td (toHtml $ show t) <> H.td h]) d+ loop _ r p End =+ (r, if null p+ then mempty+ else H.table ! A.class_ "table table-condensed col-sm-offset-1 col-md-offset-1" $+ H.caption "Route Parameters" <>+ H.tr (H.th "#" <> H.th "type" <> H.th "description") <>+ mconcat p+ )+++defaultDocumentToHtml :: Documents -> Html+defaultDocumentToHtml docs = H.docTypeHtml $ H.head headH <> H.body body+ where+ css u = H.link ! A.rel "stylesheet" ! A.href u+ headH = H.title "API document" <>+ css "//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css"++ htmlQR (Strict r) = toHtml (show r)+ htmlQR (Nullable r) = toHtml (show r ++ "?")+ htmlQR Check = toHtml ("check" :: T.Text)++ query (QueryDoc p s q t) = H.tr $+ H.td (toHtml $ T.decodeUtf8 p) <> H.td (toHtml $ strategyInfo s) <> H.td (htmlQR q) <> H.td t++ queriesH [] = mempty+ queriesH qs =+ H.table ! A.class_ "table table-condensed col-sm-offset-1 col-md-offset-1" $+ H.caption "Query Parameters" <>+ H.tr (H.th "name" <> H.th "num" <> H.th "type" <> H.th "description") <>+ mconcat (map query qs)++ method (m, MethodDoc qs d) = + H.div ! A.class_ "col-sm-offset-1 col-md-offset-1" $+ H.h4 (toHtml $ T.decodeUtf8 m) <> + (H.p ! A.class_ "col-sm-offset-1 col-md-offset-1") (toHtml d) <>+ queriesH qs++ pathH (PathDoc r ms) =+ let (route, rdoc) = routeToHtml r+ in H.div $ H.h3 route <> rdoc <> (H.div $ mconcat (map method ms))++ groupH (g, p) = H.div $ H.h2 (toHtml g) <> (mconcat $ map pathH p)++ doc (Documents n g) = H.div (mconcat $ map pathH n) <> mconcat (map groupH g)++ body = H.div ! A.class_ "container" $+ H.h1 "API document" <> doc docs
src/Data/Apiary/Param.hs view
@@ -8,6 +8,11 @@ {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE TupleSections #-} {-# LANGUAGE OverlappingInstances #-}+{-# LANGUAGE Rank2Types #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE CPP #-} module Data.Apiary.Param where @@ -17,65 +22,96 @@ 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 import Data.String(IsString)-+import Data.Text.Encoding.Error+import Text.Read import Network.Wai-import Network.Wai.Parse +#if __GLASGOW_HASKELL__ > 707+import qualified Data.Typeable+import Data.Typeable hiding (typeRep)+typeRep = Data.Typeable.typeRep+#else+import Data.Typeable+typeRep _ = typeOf (undefined :: a)+#endif+typeRep :: forall proxy a. Typeable a => proxy a -> TypeRep+{-# INLINE typeRep #-}+ jsToBool :: (IsString a, Eq a) => a -> Bool jsToBool = flip notElem jsFalse- where- jsFalse = ["false", "0", "-0", "", "null", "undefined", "NaN"]+ where+ jsFalse = ["false", "0", "-0", "", "null", "undefined", "NaN"] readPathAs :: Path a => proxy a -> T.Text -> Maybe a readPathAs _ t = readPath t -class Path a where- readPath :: T.Text -> Maybe a+data Text deriving Typeable +type Param = (S.ByteString, S.ByteString)++data File = File+ { fileParameter :: S.ByteString+ , fileName :: S.ByteString+ , fileContentType :: S.ByteString+ , fileContent :: L.ByteString+ } deriving (Show, Eq, Typeable)++data QueryRep+ = Strict TypeRep+ | Nullable TypeRep+ | Check+ deriving (Show, Eq)++class Typeable a => Path a where+ readPath :: T.Text -> Maybe a+ pathRep :: proxy a -> TypeRep+ pathRep = typeRep+ instance Path Char where- readPath s | T.null s = Nothing- | otherwise = Just $ T.head s+ readPath s+ | T.null s = Nothing+ | otherwise = Just $ T.head s -- | javascript boolean. -- when \"false\", \"0\", \"-0\", \"\", \"null\", \"undefined\", \"NaN\" then False, else True. since 0.6.0.0.-instance Path Bool where readPath = Just . jsToBool+instance Path Bool where readPath = Just . jsToBool -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 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 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 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 Path Double where readPath = readMaybe . T.unpack-instance Path Float where readPath = readMaybe . T.unpack+instance Path Double where readPath = readMaybe . T.unpack+instance Path Float where readPath = readMaybe . T.unpack -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 Path T.Text where readPath = Just; pathRep _ = typeRep (Proxy :: Proxy Text)+instance Path TL.Text where readPath = Just . TL.fromStrict; pathRep _ = typeRep (Proxy :: Proxy Text)+instance Path S.ByteString where readPath = Just . T.encodeUtf8; pathRep _ = typeRep (Proxy :: Proxy Text)+instance Path L.ByteString where readPath = Just . TL.encodeUtf8 . TL.fromStrict; pathRep _ = typeRep (Proxy :: Proxy Text)+instance Path String where readPath = Just . T.unpack; pathRep _ = typeRep (Proxy :: Proxy Text) -------------------------------------------------------------------------------- -class Query a where+class Typeable a => Query a where readQuery :: Maybe S.ByteString -> Maybe a+ queryRep :: proxy a -> QueryRep+ queryRep = Strict . typeRep -- | javascript boolean. -- when \"false\", \"0\", \"-0\", \"\", \"null\", \"undefined\", \"NaN\" then False, else True. since 0.6.0.0.-instance Query Bool where readQuery = fmap jsToBool+instance Query Bool where readQuery = fmap jsToBool instance Query Int where readQuery = maybe Nothing (readMaybe . S.unpack) instance Query Int8 where readQuery = maybe Nothing (readMaybe . S.unpack)@@ -84,29 +120,45 @@ 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 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 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+instance Query T.Text where+ readQuery = fmap $ T.decodeUtf8With lenientDecode+ queryRep _ = Strict (typeRep (Proxy :: Proxy Text)) +instance Query TL.Text where+ readQuery = fmap (TL.decodeUtf8With lenientDecode . L.fromStrict)+ queryRep _ = Strict (typeRep (Proxy :: Proxy Text))++instance Query S.ByteString where + readQuery = id+ queryRep _ = Strict (typeRep (Proxy :: Proxy Text))++instance Query L.ByteString where + readQuery = fmap L.fromStrict+ queryRep _ = Strict (typeRep (Proxy :: Proxy Text))++instance Query String where+ readQuery = fmap S.unpack+ queryRep _ = Strict (typeRep (Proxy :: Proxy Text))+ -- | 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+ queryRep _ = Nullable $ typeRep (Proxy :: Proxy a) -- | always success. for exists check. instance Query () where readQuery _ = Just ()+ queryRep _ = Check pBool :: Proxy Bool pBool = Proxy@@ -157,15 +209,18 @@ pMaybe :: proxy a -> Proxy (Maybe a) pMaybe _ = Proxy -pFile :: Proxy (File L.ByteString)+pFile :: Proxy File pFile = Proxy class ReqParam a where- reqParams :: Proxy a -> Request -> [Param] -> [File L.ByteString] -> [(S.ByteString, Maybe a)]+ reqParams :: proxy a -> Request -> [Param] -> [File] -> [(S.ByteString, Maybe a)]+ reqParamRep :: proxy a -> QueryRep -instance ReqParam (FileInfo L.ByteString) where- reqParams _ _ _ f = map (\(k,v) -> (k, Just v)) f+instance ReqParam File where+ reqParams _ _ _ = map (\f -> (fileParameter f, Just f))+ reqParamRep _ = Strict $ typeRep pFile instance Query a => ReqParam a where reqParams _ r p _ = map (\(k,v) -> (k, readQuery v)) (queryString r) ++ map (\(k,v) -> (k, readQuery $ Just v)) p+ reqParamRep = queryRep
src/Web/Apiary.hs view
@@ -1,6 +1,5 @@ module Web.Apiary - (- module Control.Monad.Apiary+ ( module Control.Monad.Apiary , module Control.Monad.Apiary.Action , module Control.Monad.Apiary.Filter , module Data.Apiary.Param
src/Web/Apiary/TH.hs view
@@ -4,7 +4,6 @@ import Control.Monad.Apiary import Control.Monad.Apiary.Action-import Network.HTTP.Types.Status import Language.Haskell.TH import Language.Haskell.TH.Quote import qualified Data.Text as T