@@ -14,7 +14,6 @@
15module Servant.Server.Internal
15module Servant.Server.Internal
16 ( module Servant.Server.Internal
16 ( module Servant.Server.Internal
17− , module Servant.Server.Internal.PathInfo
18 , module Servant.Server.Internal.Router
17 , module Servant.Server.Internal.Router
19 , module Servant.Server.Internal.RoutingApplication
18 , module Servant.Server.Internal.RoutingApplication
20 , module Servant.Server.Internal.ServantErr
19 , module Servant.Server.Internal.ServantErr
@@ -31,8 +30,6 @@ import Data.Maybe (mapMaybe, fromMaybe)
31import Data.String (fromString)
30import Data.String (fromString)
32import Data.String.Conversions (cs, (<>), ConvertibleStrings)
31import Data.String.Conversions (cs, (<>), ConvertibleStrings)
33import Data.Text (Text)
32import Data.Text (Text)
34−import qualified Data.Text as T
35−import Data.Text.Encoding (encodeUtf8)
36import Data.Typeable
33import Data.Typeable
37import GHC.TypeLits (KnownSymbol, symbolVal)
34import GHC.TypeLits (KnownSymbol, symbolVal)
38import Network.HTTP.Types hiding (Header, ResponseHeaders)
35import Network.HTTP.Types hiding (Header, ResponseHeaders)
@@ -41,11 +38,10 @@ import Network.Wai (Application, lazyRequestBody,
41 rawQueryString, requestHeaders,
38 rawQueryString, requestHeaders,
42 requestMethod, responseLBS, remoteHost,
39 requestMethod, responseLBS, remoteHost,
43 isSecure, vault, httpVersion, Response,
40 isSecure, vault, httpVersion, Response,
44− Request)
41+ Request, pathInfo)
45import Servant.API ((:<|>) (..), (:>), Capture,
42import Servant.API ((:<|>) (..), (:>), Capture,
46 Delete, Get, Header,
43 Delete, Get, Header,
47− IsSecure(..), MatrixFlag, MatrixParam,
48− MatrixParams, Patch, Post, Put,
44+ IsSecure(..), Patch, Post, Put,
49 QueryFlag, QueryParam, QueryParams,
45 QueryFlag, QueryParam, QueryParams,
50 Raw, RemoteHost, ReqBody, Vault)
46 Raw, RemoteHost, ReqBody, Vault)
51import Servant.API.ContentTypes (AcceptHeader (..),
47import Servant.API.ContentTypes (AcceptHeader (..),
@@ -54,7 +50,6 @@ import Servant.API.ContentTypes (AcceptHeader (..),
54import Servant.API.ResponseHeaders (Headers, getResponse, GetHeaders,
50import Servant.API.ResponseHeaders (Headers, getResponse, GetHeaders,
55 getHeaders)
51 getHeaders)
57−import Servant.Server.Internal.PathInfo
58import Servant.Server.Internal.Router
53import Servant.Server.Internal.Router
59import Servant.Server.Internal.RoutingApplication
54import Servant.Server.Internal.RoutingApplication
60import Servant.Server.Internal.ServantErr
55import Servant.Server.Internal.ServantErr
@@ -548,123 +543,6 @@ instance (KnownSymbol sym, HasServer sublayout)
548 examine v | v == "true" || v == "1" || v == "" = True
543 examine v | v == "true" || v == "1" || v == "" = True
549 | otherwise = False
544 | otherwise = False
551−parseMatrixText :: B.ByteString -> QueryText
552−parseMatrixText = parseQueryText
554−-- | If you use @'MatrixParam' "author" Text@ in one of the endpoints for your API,
555−-- this automatically requires your server-side handler to be a function
556−-- that takes an argument of type @'Maybe' 'Text'@.
558−-- This lets servant worry about looking it up in the query string
559−-- and turning it into a value of the type you specify, enclosed
560−-- in 'Maybe', because it may not be there and servant would then
561−-- hand you 'Nothing'.
563−-- You can control how it'll be converted from 'Text' to your type
564−-- by simply providing an instance of 'FromHttpApiData' for your type.
568−-- > type MyApi = "books" :> MatrixParam "author" Text :> Get [Book]
570−-- > server :: Server MyApi
571−-- > server = getBooksBy
572−-- > where getBooksBy :: Maybe Text -> ExceptT ServantErr IO [Book]
573−-- > getBooksBy Nothing = ...return all books...
574−-- > getBooksBy (Just author) = ...return books by the given author...
575−instance (KnownSymbol sym, FromHttpApiData a, HasServer sublayout)
576− => HasServer (MatrixParam sym a :> sublayout) where
578− type ServerT (MatrixParam sym a :> sublayout) m =
579− Maybe a -> ServerT sublayout m
581− route Proxy subserver = WithRequest $ \ request ->
582− case parsePathInfo request of
584− -> do let querytext = parseMatrixText . encodeUtf8 $ T.tail first
585− param = case lookup paramname querytext of
586− Nothing -> Nothing -- param absent from the query string
587− Just Nothing -> Nothing -- param present with no value -> Nothing
588− Just (Just v) -> parseQueryParamMaybe v -- if present, we try to convert to
590− route (Proxy :: Proxy sublayout) (feedTo subserver param)
591− _ -> route (Proxy :: Proxy sublayout) (feedTo subserver Nothing)
593− where paramname = cs $ symbolVal (Proxy :: Proxy sym)
595−-- | If you use @'MatrixParams' "authors" Text@ in one of the endpoints for your API,
596−-- this automatically requires your server-side handler to be a function
597−-- that takes an argument of type @['Text']@.
599−-- This lets servant worry about looking up 0 or more values in the query string
600−-- associated to @authors@ and turning each of them into a value of
601−-- the type you specify.
603−-- You can control how the individual values are converted from 'Text' to your type
604−-- by simply providing an instance of 'FromHttpApiData' for your type.
608−-- > type MyApi = "books" :> MatrixParams "authors" Text :> Get [Book]
610−-- > server :: Server MyApi
611−-- > server = getBooksBy
612−-- > where getBooksBy :: [Text] -> ExceptT ServantErr IO [Book]
613−-- > getBooksBy authors = ...return all books by these authors...
614−instance (KnownSymbol sym, FromHttpApiData a, HasServer sublayout)
615− => HasServer (MatrixParams sym a :> sublayout) where
617− type ServerT (MatrixParams sym a :> sublayout) m =
618− [a] -> ServerT sublayout m
620− route Proxy subserver = WithRequest $ \ request ->
621− case parsePathInfo request of
623− -> do let matrixtext = parseMatrixText . encodeUtf8 $ T.tail first
624− -- if sym is "foo", we look for matrix parameters
625− -- named "foo" or "foo[]" and call parseQueryParam on the
626− -- corresponding values
627− parameters = filter looksLikeParam matrixtext
628− values = mapMaybe (convert . snd) parameters
629− route (Proxy :: Proxy sublayout) (feedTo subserver values)
630− _ -> route (Proxy :: Proxy sublayout) (feedTo subserver [])
631− where paramname = cs $ symbolVal (Proxy :: Proxy sym)
632− looksLikeParam (name, _) = name == paramname || name == (paramname <> "[]")
633− convert Nothing = Nothing
634− convert (Just v) = parseQueryParamMaybe v
636−-- | If you use @'MatrixFlag' "published"@ in one of the endpoints for your API,
637−-- this automatically requires your server-side handler to be a function
638−-- that takes an argument of type 'Bool'.
642−-- > type MyApi = "books" :> MatrixFlag "published" :> Get [Book]
644−-- > server :: Server MyApi
645−-- > server = getBooks
646−-- > where getBooks :: Bool -> ExceptT ServantErr IO [Book]
647−-- > getBooks onlyPublished = ...return all books, or only the ones that are already published, depending on the argument...
648−instance (KnownSymbol sym, HasServer sublayout)
649− => HasServer (MatrixFlag sym :> sublayout) where
651− type ServerT (MatrixFlag sym :> sublayout) m =
652− Bool -> ServerT sublayout m
654− route Proxy subserver = WithRequest $ \ request ->
655− case parsePathInfo request of
657− -> do let matrixtext = parseMatrixText . encodeUtf8 $ T.tail first
658− param = case lookup paramname matrixtext of
659− Just Nothing -> True -- param is there, with no value
660− Just (Just v) -> examine v -- param with a value
661− Nothing -> False -- param not in the query string
662− route (Proxy :: Proxy sublayout) (feedTo subserver param)
663− _ -> route (Proxy :: Proxy sublayout) (feedTo subserver False)
664− where paramname = cs $ symbolVal (Proxy :: Proxy sym)
665− examine v | v == "true" || v == "1" || v == "" = True
668-- | Just pass the request to the underlying application and serve its response.
546-- | Just pass the request to the underlying application and serve its response.
670-- Example:
548-- Example:
@@ -762,5 +640,11 @@ instance HasServer api => HasServer (HttpVersion :> api) where
762 route Proxy subserver = WithRequest $ \req ->
640 route Proxy subserver = WithRequest $ \req ->
763 route (Proxy :: Proxy api) (feedTo subserver $ httpVersion req)
641 route (Proxy :: Proxy api) (feedTo subserver $ httpVersion req)
643+pathIsEmpty :: Request -> Bool
644+pathIsEmpty = go . pathInfo
765ct_wildcard :: B.ByteString
649ct_wildcard :: B.ByteString
766ct_wildcard = "*" <> "/" <> "*" -- Because CPP
650ct_wildcard = "*" <> "/" <> "*" -- Because CPP