git.iko.soy/typeable/servant
on master help sign in
Use http-api-data package instead of ToText/FromText
commit40d2c688975cd638aa05fa6abc4736adbe04b8ef authorNickolay Kudasov <nickolay.kudasov@gmail.com> dateThu 8 Oct 2015, 00:38 (11 years ago) parent7b60fb6
16 files changed+73−146
servant-client/servant-client.cabal+1 servant-client/src/Servant/Client.hs+18−18 servant-client/src/Servant/Common/Req.hs+4−3 servant-mock/src/Servant/Mock.hs+6−6 servant-server/servant-server.cabal+1 servant-server/src/Servant.hs−3 servant-server/src/Servant/Server/Internal.hs+25−23 servant/servant.cabal+1−1 servant/src/Servant/API.hs+4−4 servant/src/Servant/API/Header.hs−1 servant/src/Servant/API/ReqBody.hs−1 servant/src/Servant/API/Sub.hs−1 servant/src/Servant/Utils/Links.hs+11−11 servant/test/Servant/Common/TextSpec.hs−74 stack-ghc-7.8.4.yaml+1 stack.yaml+1
servant-client/servant-client.cabal+1
@@ -34,6 +34,7 @@ library
3434 , attoparsec
3535 , bytestring
3636 , exceptions
37+ , http-api-data
3738 , http-client
3839 , http-client-tls
3940 , http-media
servant-client/src/Servant/Client.hs+18−18
@@ -92,7 +92,7 @@ instance (HasClient a, HasClient b) => HasClient (a :<|> b) where
9292-- of this value at the right place in the request path.
9393--
9494-- You can control how values for this type are turned into
95−-- text by specifying a 'ToText' instance for your type.
95+-- text by specifying a 'ToHttpApiData' instance for your type.
9696--
9797-- Example:
9898--
@@ -105,7 +105,7 @@ instance (HasClient a, HasClient b) => HasClient (a :<|> b) where
105105-- > getBook = client myApi host manager
106106-- > where host = BaseUrl Http "localhost" 8080
107107-- > -- then you can just use "getBook" to query that endpoint
108−instance (KnownSymbol capture, ToText a, HasClient sublayout)
108+instance (KnownSymbol capture, ToHttpApiData a, HasClient sublayout)
109109 => HasClient (Capture capture a :> sublayout) where
110110
111111 type Client (Capture capture a :> sublayout) =
@@ -117,7 +117,7 @@ instance (KnownSymbol capture, ToText a, HasClient sublayout)
117117 baseurl
118118 manager
119119
120− where p = unpack (toText val)
120+ where p = unpack (toUrlPiece val)
121121
122122-- | If you have a 'Delete' endpoint in your API, the client
123123-- side querying function that is created when calling 'client'
@@ -205,12 +205,12 @@ instance
205205-- That function will take care of encoding this argument as Text
206206-- in the request headers.
207207--
208−-- All you need is for your type to have a 'ToText' instance.
208+-- All you need is for your type to have a 'ToHttpApiData' instance.
209209--
210210-- Example:
211211--
212212-- > newtype Referer = Referer { referrer :: Text }
213−-- > deriving (Eq, Show, Generic, FromText, ToText)
213+-- > deriving (Eq, Show, Generic, FromText, ToHttpApiData)
214214-- >
215215-- > -- GET /view-my-referer
216216-- > type MyApi = "view-my-referer" :> Header "Referer" Referer :> Get '[JSON] Referer
@@ -223,7 +223,7 @@ instance
223223-- > where host = BaseUrl Http "localhost" 8080
224224-- > -- then you can just use "viewRefer" to query that endpoint
225225-- > -- specifying Nothing or e.g Just "http://haskell.org/" as arguments
226−instance (KnownSymbol sym, ToText a, HasClient sublayout)
226+instance (KnownSymbol sym, ToHttpApiData a, HasClient sublayout)
227227 => HasClient (Header sym a :> sublayout) where
228228
229229 type Client (Header sym a :> sublayout) =
@@ -368,7 +368,7 @@ instance
368368-- of inserting a textual representation of this value in the query string.
369369--
370370-- You can control how values for your type are turned into
371−-- text by specifying a 'ToText' instance for your type.
371+-- text by specifying a 'ToHttpApiData' instance for your type.
372372--
373373-- Example:
374374--
@@ -383,7 +383,7 @@ instance
383383-- > -- then you can just use "getBooksBy" to query that endpoint.
384384-- > -- 'getBooksBy Nothing' for all books
385385-- > -- 'getBooksBy (Just "Isaac Asimov")' to get all books by Isaac Asimov
386−instance (KnownSymbol sym, ToText a, HasClient sublayout)
386+instance (KnownSymbol sym, ToHttpApiData a, HasClient sublayout)
387387 => HasClient (QueryParam sym a :> sublayout) where
388388
389389 type Client (QueryParam sym a :> sublayout) =
@@ -401,7 +401,7 @@ instance (KnownSymbol sym, ToText a, HasClient sublayout)
401401
402402 where pname = cs pname'
403403 pname' = symbolVal (Proxy :: Proxy sym)
404− mparamText = fmap toText mparam
404+ mparamText = fmap toQueryParam mparam
405405
406406-- | If you use a 'QueryParams' in one of your endpoints in your API,
407407-- the corresponding querying function will automatically take
@@ -415,7 +415,7 @@ instance (KnownSymbol sym, ToText a, HasClient sublayout)
415415-- under the same query string parameter name.
416416--
417417-- You can control how values for your type are turned into
418−-- text by specifying a 'ToText' instance for your type.
418+-- text by specifying a 'ToHttpApiData' instance for your type.
419419--
420420-- Example:
421421--
@@ -431,7 +431,7 @@ instance (KnownSymbol sym, ToText a, HasClient sublayout)
431431-- > -- 'getBooksBy []' for all books
432432-- > -- 'getBooksBy ["Isaac Asimov", "Robert A. Heinlein"]'
433433-- > -- to get all books by Asimov and Heinlein
434−instance (KnownSymbol sym, ToText a, HasClient sublayout)
434+instance (KnownSymbol sym, ToHttpApiData a, HasClient sublayout)
435435 => HasClient (QueryParams sym a :> sublayout) where
436436
437437 type Client (QueryParams sym a :> sublayout) =
@@ -447,7 +447,7 @@ instance (KnownSymbol sym, ToText a, HasClient sublayout)
447447
448448 where pname = cs pname'
449449 pname' = symbolVal (Proxy :: Proxy sym)
450− paramlist' = map (Just . toText) paramlist
450+ paramlist' = map (Just . toQueryParam) paramlist
451451
452452-- | If you use a 'QueryFlag' in one of your endpoints in your API,
453453-- the corresponding querying function will automatically take
@@ -498,7 +498,7 @@ instance (KnownSymbol sym, HasClient sublayout)
498498-- of inserting a textual representation of this value in the query string.
499499--
500500-- You can control how values for your type are turned into
501−-- text by specifying a 'ToText' instance for your type.
501+-- text by specifying a 'ToHttpApiData' instance for your type.
502502--
503503-- Example:
504504--
@@ -513,7 +513,7 @@ instance (KnownSymbol sym, HasClient sublayout)
513513-- > -- then you can just use "getBooksBy" to query that endpoint.
514514-- > -- 'getBooksBy Nothing' for all books
515515-- > -- 'getBooksBy (Just "Isaac Asimov")' to get all books by Isaac Asimov
516−instance (KnownSymbol sym, ToText a, HasClient sublayout)
516+instance (KnownSymbol sym, ToHttpApiData a, HasClient sublayout)
517517 => HasClient (MatrixParam sym a :> sublayout) where
518518
519519 type Client (MatrixParam sym a :> sublayout) =
@@ -529,7 +529,7 @@ instance (KnownSymbol sym, ToText a, HasClient sublayout)
529529 baseurl manager
530530
531531 where pname = symbolVal (Proxy :: Proxy sym)
532− mparamText = fmap (cs . toText) mparam
532+ mparamText = fmap (cs . toQueryParam) mparam
533533
534534-- | If you use a 'MatrixParams' in one of your endpoints in your API,
535535-- the corresponding querying function will automatically take an
@@ -543,7 +543,7 @@ instance (KnownSymbol sym, ToText a, HasClient sublayout)
543543-- same matrix string parameter name.
544544--
545545-- You can control how values for your type are turned into text by
546−-- specifying a 'ToText' instance for your type.
546+-- specifying a 'ToHttpApiData' instance for your type.
547547--
548548-- Example:
549549--
@@ -559,7 +559,7 @@ instance (KnownSymbol sym, ToText a, HasClient sublayout)
559559-- > -- 'getBooksBy []' for all books
560560-- > -- 'getBooksBy ["Isaac Asimov", "Robert A. Heinlein"]'
561561-- > -- to get all books by Asimov and Heinlein
562−instance (KnownSymbol sym, ToText a, HasClient sublayout)
562+instance (KnownSymbol sym, ToHttpApiData a, HasClient sublayout)
563563 => HasClient (MatrixParams sym a :> sublayout) where
564564
565565 type Client (MatrixParams sym a :> sublayout) =
@@ -575,7 +575,7 @@ instance (KnownSymbol sym, ToText a, HasClient sublayout)
575575
576576 where pname = cs pname'
577577 pname' = symbolVal (Proxy :: Proxy sym)
578− paramlist' = map (Just . toText) paramlist
578+ paramlist' = map (Just . toQueryParam) paramlist
579579
580580-- | If you use a 'MatrixFlag' in one of your endpoints in your API,
581581-- the corresponding querying function will automatically take an
servant-client/src/Servant/Common/Req.hs+4−3
@@ -26,10 +26,11 @@ import qualified Network.HTTP.Types.Header as HTTP
2626import Network.URI hiding (path)
2727import Servant.API.ContentTypes
2828import Servant.Common.BaseUrl
29−import Servant.Common.Text
3029
3130import qualified Network.HTTP.Client as Client
3231
32+import Web.HttpApiData
33+
3334data ServantError
3435 = FailureResponse
3536 { responseStatus :: Status
@@ -86,9 +87,9 @@ appendToQueryString pname pvalue req =
8687 req { qs = qs req ++ [(pname, pvalue)]
8788 }
8889
89−addHeader :: ToText a => String -> a -> Req -> Req
90+addHeader :: ToHttpApiData a => String -> a -> Req -> Req
9091addHeader name val req = req { headers = headers req
91− ++ [(name, toText val)]
92+ ++ [(name, decodeUtf8 (toHeader val))]
9293 }
9394
9495setRQBody :: ByteString -> MediaType -> Req -> Req
servant-mock/src/Servant/Mock.hs+6−6
@@ -107,7 +107,7 @@ instance (HasMock a, HasMock b) => HasMock (a :<|> b) where
107107instance (KnownSymbol path, HasMock rest) => HasMock (path :> rest) where
108108 mock _ = mock (Proxy :: Proxy rest)
109109
110−instance (KnownSymbol s, FromText a, HasMock rest) => HasMock (Capture s a :> rest) where
110+instance (KnownSymbol s, FromHttpApiData a, HasMock rest) => HasMock (Capture s a :> rest) where
111111 mock _ = \_ -> mock (Proxy :: Proxy rest)
112112
113113instance (AllCTUnrender ctypes a, HasMock rest) => HasMock (ReqBody ctypes a :> rest) where
@@ -125,29 +125,29 @@ instance HasMock rest => HasMock (Vault :> rest) where
125125instance HasMock rest => HasMock (HttpVersion :> rest) where
126126 mock _ = \_ -> mock (Proxy :: Proxy rest)
127127
128−instance (KnownSymbol s, FromText a, HasMock rest)
128+instance (KnownSymbol s, FromHttpApiData a, HasMock rest)
129129 => HasMock (QueryParam s a :> rest) where
130130 mock _ = \_ -> mock (Proxy :: Proxy rest)
131131
132−instance (KnownSymbol s, FromText a, HasMock rest)
132+instance (KnownSymbol s, FromHttpApiData a, HasMock rest)
133133 => HasMock (QueryParams s a :> rest) where
134134 mock _ = \_ -> mock (Proxy :: Proxy rest)
135135
136136instance (KnownSymbol s, HasMock rest) => HasMock (QueryFlag s :> rest) where
137137 mock _ = \_ -> mock (Proxy :: Proxy rest)
138138
139−instance (KnownSymbol s, FromText a, HasMock rest)
139+instance (KnownSymbol s, FromHttpApiData a, HasMock rest)
140140 => HasMock (MatrixParam s a :> rest) where
141141 mock _ = \_ -> mock (Proxy :: Proxy rest)
142142
143−instance (KnownSymbol s, FromText a, HasMock rest)
143+instance (KnownSymbol s, FromHttpApiData a, HasMock rest)
144144 => HasMock (MatrixParams s a :> rest) where
145145 mock _ = \_ -> mock (Proxy :: Proxy rest)
146146
147147instance (KnownSymbol s, HasMock rest) => HasMock (MatrixFlag s :> rest) where
148148 mock _ = \_ -> mock (Proxy :: Proxy rest)
149149
150−instance (KnownSymbol h, FromText a, HasMock rest) => HasMock (Header h a :> rest) where
150+instance (KnownSymbol h, FromHttpApiData a, HasMock rest) => HasMock (Header h a :> rest) where
151151 mock _ = \_ -> mock (Proxy :: Proxy rest)
152152
153153instance (Arbitrary a, AllCTRender ctypes a) => HasMock (Delete ctypes a) where
servant-server/servant-server.cabal+1
@@ -48,6 +48,7 @@ library
4848 , attoparsec >= 0.12 && < 0.14
4949 , bytestring >= 0.10 && < 0.11
5050 , containers >= 0.5 && < 0.6
51+ , http-api-data
5152 , http-types >= 0.8 && < 0.9
5253 , network-uri >= 2.6 && < 2.7
5354 , mtl >= 2 && < 3
servant-server/src/Servant.hs−3
@@ -5,8 +5,6 @@ module Servant (
55 module Servant.API,
66 -- | For implementing servers for servant APIs.
77 module Servant.Server,
8− -- | Using your types in request paths and query string parameters
9− module Servant.Common.Text,
108 -- | Utilities on top of the servant core
119 module Servant.Utils.Links,
1210 module Servant.Utils.StaticFiles,
@@ -16,7 +14,6 @@ module Servant (
1614
1715import Data.Proxy
1816import Servant.API
19−import Servant.Common.Text
2017import Servant.Server
2118import Servant.Utils.Links
2219import Servant.Utils.StaticFiles
servant-server/src/Servant/Server/Internal.hs+25−23
@@ -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
servant/servant.cabal+1−1
@@ -52,6 +52,7 @@ library
5252 , bytestring == 0.10.*
5353 , bytestring-conversion == 0.3.*
5454 , case-insensitive >= 1.2
55+ , http-api-data
5556 , http-media >= 0.4 && < 0.7
5657 , http-types == 0.8.*
5758 , text >= 1 && < 2
@@ -92,7 +93,6 @@ test-suite spec
9293 other-modules:
9394 Servant.API.ContentTypesSpec
9495 Servant.API.ResponseHeadersSpec
95− Servant.Common.TextSpec
9696 Servant.Utils.LinksSpec
9797 build-depends:
9898 base == 4.*
servant/src/Servant/API.hs+4−4
@@ -50,9 +50,9 @@ module Servant.API (
5050 module Servant.API.Raw,
5151 -- | Plugging in a wai 'Network.Wai.Application', serving directories
5252
53− -- * FromText and ToText
54− module Servant.Common.Text,
55− -- | Classes and instances for types that can be converted to and from @Text@
53+ -- * FromHttpApiData and ToHttpApiData
54+ module Web.HttpApiData,
55+ -- | Classes and instances for types that can be converted to and from HTTP API data.
5656
5757 -- * Utilities
5858 module Servant.Utils.Links,
@@ -88,7 +88,7 @@ import Servant.API.ResponseHeaders (AddHeader (addHeader),
8888 getHeadersHList, getResponse)
8989import Servant.API.Sub ((:>))
9090import Servant.API.Vault (Vault)
91−import Servant.Common.Text (FromText (..), ToText (..))
91+import Web.HttpApiData (FromHttpApiData (..), ToHttpApiData (..))
9292import Servant.Utils.Links (HasLink (..), IsElem, IsElem',
9393 URI (..), safeLink)
9494
servant/src/Servant/API/Header.hs−1
@@ -23,7 +23,6 @@ data Header (sym :: Symbol) a = Header a
2323
2424-- $setup
2525-- >>> import Servant.API
26−-- >>> import Servant.Common.Text
2726-- >>> import Data.Aeson
2827-- >>> import Data.Text
2928-- >>> data Book
servant/src/Servant/API/ReqBody.hs−1
@@ -16,7 +16,6 @@ data ReqBody (contentTypes :: [*]) a
1616
1717-- $setup
1818-- >>> import Servant.API
19−-- >>> import Servant.Common.Text
2019-- >>> import Data.Aeson
2120-- >>> import Data.Text
2221-- >>> data Book
servant/src/Servant/API/Sub.hs−1
@@ -20,7 +20,6 @@ infixr 9 :>
2020
2121-- $setup
2222-- >>> import Servant.API
23−-- >>> import Servant.Common.Text
2423-- >>> import Data.Aeson
2524-- >>> import Data.Text
2625-- >>> data World
servant/src/Servant/Utils/Links.hs+11−11
@@ -113,7 +113,7 @@ import Network.URI ( URI(..), escapeURIString, isUnreserved )
113113import GHC.TypeLits ( KnownSymbol, symbolVal )
114114import GHC.Exts(Constraint)
115115
116−import Servant.Common.Text
116+import Web.HttpApiData
117117import Servant.API.Capture ( Capture )
118118import Servant.API.ReqBody ( ReqBody )
119119import Servant.API.QueryParam ( QueryParam, QueryParams, QueryFlag )
@@ -271,22 +271,22 @@ instance (KnownSymbol sym, HasLink sub) => HasLink (sym :> sub) where
271271
272272
273273-- QueryParam instances
274−instance (KnownSymbol sym, ToText v, HasLink sub)
274+instance (KnownSymbol sym, ToHttpApiData v, HasLink sub)
275275 => HasLink (QueryParam sym v :> sub) where
276276 type MkLink (QueryParam sym v :> sub) = Maybe v -> MkLink sub
277277 toLink _ l mv =
278278 toLink (Proxy :: Proxy sub) $
279− maybe id (addQueryParam . SingleParam k . toText) mv l
279+ maybe id (addQueryParam . SingleParam k . toQueryParam) mv l
280280 where
281281 k :: String
282282 k = symbolVal (Proxy :: Proxy sym)
283283
284−instance (KnownSymbol sym, ToText v, HasLink sub)
284+instance (KnownSymbol sym, ToHttpApiData v, HasLink sub)
285285 => HasLink (QueryParams sym v :> sub) where
286286 type MkLink (QueryParams sym v :> sub) = [v] -> MkLink sub
287287 toLink _ l =
288288 toLink (Proxy :: Proxy sub) .
289− foldl' (\l' v -> addQueryParam (ArrayElemParam k (toText v)) l') l
289+ foldl' (\l' v -> addQueryParam (ArrayElemParam k (toQueryParam v)) l') l
290290 where
291291 k = symbolVal (Proxy :: Proxy sym)
292292
@@ -301,21 +301,21 @@ instance (KnownSymbol sym, HasLink sub)
301301 k = symbolVal (Proxy :: Proxy sym)
302302
303303-- MatrixParam instances
304−instance (KnownSymbol sym, ToText v, HasLink sub)
304+instance (KnownSymbol sym, ToHttpApiData v, HasLink sub)
305305 => HasLink (MatrixParam sym v :> sub) where
306306 type MkLink (MatrixParam sym v :> sub) = Maybe v -> MkLink sub
307307 toLink _ l mv =
308308 toLink (Proxy :: Proxy sub) $
309− maybe id (addMatrixParam . SingleParam k . toText) mv l
309+ maybe id (addMatrixParam . SingleParam k . toQueryParam) mv l
310310 where
311311 k = symbolVal (Proxy :: Proxy sym)
312312
313−instance (KnownSymbol sym, ToText v, HasLink sub)
313+instance (KnownSymbol sym, ToHttpApiData v, HasLink sub)
314314 => HasLink (MatrixParams sym v :> sub) where
315315 type MkLink (MatrixParams sym v :> sub) = [v] -> MkLink sub
316316 toLink _ l =
317317 toLink (Proxy :: Proxy sub) .
318− foldl' (\l' v -> addMatrixParam (ArrayElemParam k (toText v)) l') l
318+ foldl' (\l' v -> addMatrixParam (ArrayElemParam k (toQueryParam v)) l') l
319319 where
320320 k = symbolVal (Proxy :: Proxy sym)
321321
@@ -334,12 +334,12 @@ instance HasLink sub => HasLink (ReqBody ct a :> sub) where
334334 type MkLink (ReqBody ct a :> sub) = MkLink sub
335335 toLink _ = toLink (Proxy :: Proxy sub)
336336
337−instance (ToText v, HasLink sub)
337+instance (ToHttpApiData v, HasLink sub)
338338 => HasLink (Capture sym v :> sub) where
339339 type MkLink (Capture sym v :> sub) = v -> MkLink sub
340340 toLink _ l v =
341341 toLink (Proxy :: Proxy sub) $
342− addSegment (escape . unpack $ toText v) l
342+ addSegment (escape . unpack $ toUrlPiece v) l
343343
344344instance HasLink sub => HasLink (Header sym a :> sub) where
345345 type MkLink (Header sym a :> sub) = MkLink sub
servant/test/Servant/Common/TextSpec.hsdeleted−74
@@ -1,74 +0,0 @@
1−{-# LANGUAGE CPP #-}
2−module Servant.Common.TextSpec where
3−
4−import Data.Int (Int16, Int32, Int64, Int8)
5−import Data.Text (Text)
6−import Data.Word (Word16, Word32, Word64, Word8
7−#if !MIN_VERSION_base(4,8,0)
8− , Word
9−#endif
10− )
11−import Servant.Common.Text
12−import Test.Hspec
13−import Test.QuickCheck
14−import Test.QuickCheck.Instances ()
15−
16−spec :: Spec
17−spec = describe "Servant.Common.Text" $ do
18−
19− context "FromText and ToText laws" $ do
20−
21− it "holds for Text" $
22− property $ \x -> textLaw (x :: Text)
23−
24− it "holds for String" $
25− property $ \x -> textLaw (x :: String)
26−
27− it "holds for Bool" $
28− property $ \x -> textLaw (x :: Bool)
29−
30− it "holds for Int" $
31− property $ \x -> textLaw (x :: Int)
32−
33− it "holds for Int8" $
34− property $ \x -> textLaw (x :: Int8)
35−
36− it "holds for Int16" $
37− property $ \x -> textLaw (x :: Int16)
38−
39− it "holds for Int32" $
40− property $ \x -> textLaw (x :: Int32)
41−
42− it "holds for Int64" $
43− property $ \x -> textLaw (x :: Int64)
44−
45− it "holds for Word" $
46− property $ \x -> textLaw (x :: Word)
47−
48− it "holds for Word8" $
49− property $ \x -> textLaw (x :: Word8)
50−
51− it "holds for Word16" $
52− property $ \x -> textLaw (x :: Word16)
53−
54− it "holds for Word32" $
55− property $ \x -> textLaw (x :: Word32)
56−
57− it "holds for Word64" $
58− property $ \x -> textLaw (x :: Word64)
59−
60− it "holds for Integer" $
61− property $ \x -> textLaw (x :: Integer)
62−
63− -- The following two properties are only reasonably expected to hold up
64− -- to a certain precision.
65− --
66− -- http://en.wikipedia.org/wiki/Floating_point#Internal_representation
67− it "holds for Double" $
68− property $ \x -> textLaw (x :: Double)
69−
70− it "holds for Float" $
71− property $ \x -> textLaw (x :: Float)
72−
73−textLaw :: (FromText a, ToText a, Eq a) => a -> Bool
74−textLaw a = fromText (toText a) == Just a
stack-ghc-7.8.4.yaml+1
@@ -21,4 +21,5 @@ extra-deps:
2121- socket-io-1.3.3
2222- stm-delay-0.1.1.1
2323- control-monad-omega-0.3.1
24+- http-api-data-0.1.0
2425resolver: lts-2.22
stack.yaml+1
@@ -16,4 +16,5 @@ packages:
1616extra-deps:
1717- engine-io-wai-1.0.2
1818- control-monad-omega-0.3.1
19+- http-api-data-0.1.0
1920resolver: nightly-2015-09-10