@@ -32,7 +32,7 @@ import Data.String (fromString)
3232import Data.String.Conversions (cs, (<>), ConvertibleStrings)
3333import Data.Text (Text)
3434import qualified Data.Text as T
35−import Data.Text.Encoding (decodeUtf8, encodeUtf8)
35+import Data.Text.Encoding (encodeUtf8)
3636import Data.Typeable
3737import GHC.TypeLits (KnownSymbol, symbolVal)
3838import Network.HTTP.Types hiding (Header, ResponseHeaders)
@@ -53,13 +53,15 @@ import Servant.API.ContentTypes (AcceptHeader (..),
5353 AllCTUnrender (..))
5454import Servant.API.ResponseHeaders (Headers, getResponse, GetHeaders,
5555 getHeaders)
56−import Servant.Common.Text (FromText, fromText)
5756
5857import Servant.Server.Internal.PathInfo
5958import Servant.Server.Internal.Router
6059import Servant.Server.Internal.RoutingApplication
6160import Servant.Server.Internal.ServantErr
6261
62+import Web.HttpApiData (FromHttpApiData)
63+import Web.HttpApiData.Internal (parseUrlPieceMaybe, parseHeaderMaybe, parseQueryParamMaybe)
64+
6365class HasServer layout where
6466 type ServerT layout (m :: * -> *) :: *
6567
@@ -89,8 +91,8 @@ instance (HasServer a, HasServer b) => HasServer (a :<|> b) where
8991 where pa = Proxy :: Proxy a
9092 pb = Proxy :: Proxy b
9193
92−captured :: FromText a => proxy (Capture sym a) -> Text -> Maybe a
93−captured _ = fromText
94+captured :: FromHttpApiData a => proxy (Capture sym a) -> Text -> Maybe a
95+captured _ = parseUrlPieceMaybe
9496
9597-- | If you use 'Capture' in one of the endpoints for your API,
9698-- this automatically requires your server-side handler to be a function
@@ -99,7 +101,7 @@ captured _ = fromText
99101-- it into a value of the type you specify.
100102--
101103-- You can control how it'll be converted from 'Text' to your type
102−-- by simply providing an instance of 'FromText' for your type.
104+-- by simply providing an instance of 'FromHttpApiData' for your type.
103105--
104106-- Example:
105107--
@@ -109,7 +111,7 @@ captured _ = fromText
109111-- > server = getBook
110112-- > where getBook :: Text -> ExceptT ServantErr IO Book
111113-- > getBook isbn = ...
112−instance (KnownSymbol capture, FromText a, HasServer sublayout)
114+instance (KnownSymbol capture, FromHttpApiData a, HasServer sublayout)
113115 => HasServer (Capture capture a :> sublayout) where
114116
115117 type ServerT (Capture capture a :> sublayout) m =
@@ -282,12 +284,12 @@ instance
282284-- This lets servant worry about extracting it from the request and turning
283285-- it into a value of the type you specify.
284286--
285−-- All it asks is for a 'FromText' instance.
287+-- All it asks is for a 'FromHttpApiData' instance.
286288--
287289-- Example:
288290--
289291-- > newtype Referer = Referer Text
290−-- > deriving (Eq, Show, FromText, ToText)
292+-- > deriving (Eq, Show, FromHttpApiData, ToText)
291293-- >
292294-- > -- GET /view-my-referer
293295-- > type MyApi = "view-my-referer" :> Header "Referer" Referer :> Get '[JSON] Referer
@@ -296,14 +298,14 @@ instance
296298-- > server = viewReferer
297299-- > where viewReferer :: Referer -> ExceptT ServantErr IO referer
298300-- > viewReferer referer = return referer
299−instance (KnownSymbol sym, FromText a, HasServer sublayout)
301+instance (KnownSymbol sym, FromHttpApiData a, HasServer sublayout)
300302 => HasServer (Header sym a :> sublayout) where
301303
302304 type ServerT (Header sym a :> sublayout) m =
303305 Maybe a -> ServerT sublayout m
304306
305307 route Proxy subserver = WithRequest $ \ request ->
306− let mheader = fromText . decodeUtf8 =<< lookup str (requestHeaders request)
308+ let mheader = parseHeaderMaybe =<< lookup str (requestHeaders request)
307309 in route (Proxy :: Proxy sublayout) (feedTo subserver mheader)
308310 where str = fromString $ symbolVal (Proxy :: Proxy sym)
309311
@@ -451,7 +453,7 @@ instance
451453-- hand you 'Nothing'.
452454--
453455-- You can control how it'll be converted from 'Text' to your type
454−-- by simply providing an instance of 'FromText' for your type.
456+-- by simply providing an instance of 'FromHttpApiData' for your type.
455457--
456458-- Example:
457459--
@@ -462,7 +464,7 @@ instance
462464-- > where getBooksBy :: Maybe Text -> ExceptT ServantErr IO [Book]
463465-- > getBooksBy Nothing = ...return all books...
464466-- > getBooksBy (Just author) = ...return books by the given author...
465−instance (KnownSymbol sym, FromText a, HasServer sublayout)
467+instance (KnownSymbol sym, FromHttpApiData a, HasServer sublayout)
466468 => HasServer (QueryParam sym a :> sublayout) where
467469
468470 type ServerT (QueryParam sym a :> sublayout) m =
@@ -474,7 +476,7 @@ instance (KnownSymbol sym, FromText a, HasServer sublayout)
474476 case lookup paramname querytext of
475477 Nothing -> Nothing -- param absent from the query string
476478 Just Nothing -> Nothing -- param present with no value -> Nothing
477− Just (Just v) -> fromText v -- if present, we try to convert to
479+ Just (Just v) -> parseQueryParamMaybe v -- if present, we try to convert to
478480 -- the right type
479481 in route (Proxy :: Proxy sublayout) (feedTo subserver param)
480482 where paramname = cs $ symbolVal (Proxy :: Proxy sym)
@@ -488,7 +490,7 @@ instance (KnownSymbol sym, FromText a, HasServer sublayout)
488490-- the type you specify.
489491--
490492-- You can control how the individual values are converted from 'Text' to your type
491−-- by simply providing an instance of 'FromText' for your type.
493+-- by simply providing an instance of 'FromHttpApiData' for your type.
492494--
493495-- Example:
494496--
@@ -498,7 +500,7 @@ instance (KnownSymbol sym, FromText a, HasServer sublayout)
498500-- > server = getBooksBy
499501-- > where getBooksBy :: [Text] -> ExceptT ServantErr IO [Book]
500502-- > getBooksBy authors = ...return all books by these authors...
501−instance (KnownSymbol sym, FromText a, HasServer sublayout)
503+instance (KnownSymbol sym, FromHttpApiData a, HasServer sublayout)
502504 => HasServer (QueryParams sym a :> sublayout) where
503505
504506 type ServerT (QueryParams sym a :> sublayout) m =
@@ -507,7 +509,7 @@ instance (KnownSymbol sym, FromText a, HasServer sublayout)
507509 route Proxy subserver = WithRequest $ \ request ->
508510 let querytext = parseQueryText $ rawQueryString request
509511 -- if sym is "foo", we look for query string parameters
510− -- named "foo" or "foo[]" and call fromText on the
512+ -- named "foo" or "foo[]" and call parseQueryParam on the
511513 -- corresponding values
512514 parameters = filter looksLikeParam querytext
513515 values = mapMaybe (convert . snd) parameters
@@ -515,7 +517,7 @@ instance (KnownSymbol sym, FromText a, HasServer sublayout)
515517 where paramname = cs $ symbolVal (Proxy :: Proxy sym)
516518 looksLikeParam (name, _) = name == paramname || name == (paramname <> "[]")
517519 convert Nothing = Nothing
518− convert (Just v) = fromText v
520+ convert (Just v) = parseQueryParamMaybe v
519521
520522-- | If you use @'QueryFlag' "published"@ in one of the endpoints for your API,
521523-- this automatically requires your server-side handler to be a function
@@ -559,7 +561,7 @@ parseMatrixText = parseQueryText
559561-- hand you 'Nothing'.
560562--
561563-- You can control how it'll be converted from 'Text' to your type
562−-- by simply providing an instance of 'FromText' for your type.
564+-- by simply providing an instance of 'FromHttpApiData' for your type.
563565--
564566-- Example:
565567--
@@ -570,7 +572,7 @@ parseMatrixText = parseQueryText
570572-- > where getBooksBy :: Maybe Text -> ExceptT ServantErr IO [Book]
571573-- > getBooksBy Nothing = ...return all books...
572574-- > getBooksBy (Just author) = ...return books by the given author...
573−instance (KnownSymbol sym, FromText a, HasServer sublayout)
575+instance (KnownSymbol sym, FromHttpApiData a, HasServer sublayout)
574576 => HasServer (MatrixParam sym a :> sublayout) where
575577
576578 type ServerT (MatrixParam sym a :> sublayout) m =
@@ -583,7 +585,7 @@ instance (KnownSymbol sym, FromText a, HasServer sublayout)
583585 param = case lookup paramname querytext of
584586 Nothing -> Nothing -- param absent from the query string
585587 Just Nothing -> Nothing -- param present with no value -> Nothing
586− Just (Just v) -> fromText v -- if present, we try to convert to
588+ Just (Just v) -> parseQueryParamMaybe v -- if present, we try to convert to
587589 -- the right type
588590 route (Proxy :: Proxy sublayout) (feedTo subserver param)
589591 _ -> route (Proxy :: Proxy sublayout) (feedTo subserver Nothing)
@@ -599,7 +601,7 @@ instance (KnownSymbol sym, FromText a, HasServer sublayout)
599601-- the type you specify.
600602--
601603-- You can control how the individual values are converted from 'Text' to your type
602−-- by simply providing an instance of 'FromText' for your type.
604+-- by simply providing an instance of 'FromHttpApiData' for your type.
603605--
604606-- Example:
605607--
@@ -609,7 +611,7 @@ instance (KnownSymbol sym, FromText a, HasServer sublayout)
609611-- > server = getBooksBy
610612-- > where getBooksBy :: [Text] -> ExceptT ServantErr IO [Book]
611613-- > getBooksBy authors = ...return all books by these authors...
612−instance (KnownSymbol sym, FromText a, HasServer sublayout)
614+instance (KnownSymbol sym, FromHttpApiData a, HasServer sublayout)
613615 => HasServer (MatrixParams sym a :> sublayout) where
614616
615617 type ServerT (MatrixParams sym a :> sublayout) m =
@@ -620,7 +622,7 @@ instance (KnownSymbol sym, FromText a, HasServer sublayout)
620622 (first : _)
621623 -> do let matrixtext = parseMatrixText . encodeUtf8 $ T.tail first
622624 -- if sym is "foo", we look for matrix parameters
623− -- named "foo" or "foo[]" and call fromText on the
625+ -- named "foo" or "foo[]" and call parseQueryParam on the
624626 -- corresponding values
625627 parameters = filter looksLikeParam matrixtext
626628 values = mapMaybe (convert . snd) parameters
@@ -629,7 +631,7 @@ instance (KnownSymbol sym, FromText a, HasServer sublayout)
629631 where paramname = cs $ symbolVal (Proxy :: Proxy sym)
630632 looksLikeParam (name, _) = name == paramname || name == (paramname <> "[]")
631633 convert Nothing = Nothing
632− convert (Just v) = fromText v
634+ convert (Just v) = parseQueryParamMaybe v
633635
634636-- | If you use @'MatrixFlag' "published"@ in one of the endpoints for your API,
635637-- this automatically requires your server-side handler to be a function