@@ -97,6 +97,10 @@
97{-# LANGUAGE ScopedTypeVariables #-}
97{-# LANGUAGE ScopedTypeVariables #-}
98{-# LANGUAGE TypeFamilies #-}
98{-# LANGUAGE TypeFamilies #-}
100+#if MIN_VERSION_base(4,9,0)
101+{-# LANGUAGE UndecidableInstances #-}
100#if __GLASGOW_HASKELL__ >= 800
104#if __GLASGOW_HASKELL__ >= 800
101{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}
105{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}
@@ -143,6 +147,7 @@ module Network.HTTP.Req
143 , FormUrlEncodedParam
147 , FormUrlEncodedParam
144 , HttpBody (..)
148 , HttpBody (..)
145 , ProvidesBody
149 , ProvidesBody
146 -- ** Optional parameters
151 -- ** Optional parameters
147 -- $optional-parameters
152 -- $optional-parameters
@@ -211,7 +216,6 @@ import Data.List (nubBy)
211import Data.List.NonEmpty (NonEmpty (..))
216import Data.List.NonEmpty (NonEmpty (..))
212import Data.Proxy
217import Data.Proxy
213import Data.Semigroup hiding (Option, option)
218import Data.Semigroup hiding (Option, option)
214−import Data.Text (Text)
215import Data.Typeable (Typeable)
219import Data.Typeable (Typeable)
216import GHC.Generics
220import GHC.Generics
217import GHC.TypeLits
221import GHC.TypeLits
@@ -224,6 +228,7 @@ import qualified Data.ByteString as B
224import qualified Data.ByteString.Lazy as BL
228import qualified Data.ByteString.Lazy as BL
225import qualified Data.CaseInsensitive as CI
229import qualified Data.CaseInsensitive as CI
226import qualified Data.List.NonEmpty as NE
230import qualified Data.List.NonEmpty as NE
231+import qualified Data.Text as T
227import qualified Data.Text.Encoding as T
232import qualified Data.Text.Encoding as T
228import qualified Network.Connection as NC
233import qualified Network.Connection as NC
229import qualified Network.HTTP.Client as L
234import qualified Network.HTTP.Client as L
@@ -233,6 +238,12 @@ import qualified Network.HTTP.Req.AWS as AWS
233import qualified Network.HTTP.Req.OAuth1 as OAuth1
238import qualified Network.HTTP.Req.OAuth1 as OAuth1
234import qualified Network.HTTP.Types as Y
239import qualified Network.HTTP.Types as Y
241+#if MIN_VERSION_base(4,9,0)
242+import Data.Kind (Constraint)
244+import GHC.Exts (Constraint)
236----------------------------------------------------------------------------
247----------------------------------------------------------------------------
237-- Making a request
248-- Making a request
@@ -369,7 +380,7 @@ req
369 , HttpMethod method
380 , HttpMethod method
370 , HttpBody body
381 , HttpBody body
371 , HttpResponse response
382 , HttpResponse response
372− , AllowsBody method ~ ProvidesBody body )
383+ , HttpBodyAllowed (AllowsBody method) (ProvidesBody body) )
373 => method -- ^ HTTP method
384 => method -- ^ HTTP method
374 -> Url scheme -- ^ 'Url' — location of resource
385 -> Url scheme -- ^ 'Url' — location of resource
375 -> body -- ^ Body of the request
386 -> body -- ^ Body of the request
@@ -657,20 +668,20 @@ instance HttpMethod method => RequestComponent (Womb "method" method) where
657-- > https "юникод.рф"
668-- > https "юникод.рф"
658-- > -- https://%D1%8E%D0%BD%D0%B8%D0%BA%D0%BE%D0%B4.%D1%80%D1%84
669-- > -- https://%D1%8E%D0%BD%D0%B8%D0%BA%D0%BE%D0%B4.%D1%80%D1%84
660−data Url (scheme :: Scheme) = Url Scheme (NonEmpty Text)
671+data Url (scheme :: Scheme) = Url Scheme (NonEmpty T.Text)
661 -- NOTE The second value is path segments in reversed order.
672 -- NOTE The second value is path segments in reversed order.
662 deriving (Eq, Ord, Show, Data, Typeable, Generic)
673 deriving (Eq, Ord, Show, Data, Typeable, Generic)
664-- | Given host name, produce a 'Url' which have “http” as its scheme and
675-- | Given host name, produce a 'Url' which have “http” as its scheme and
665-- empty path. This also sets port to @80@.
676-- empty path. This also sets port to @80@.
667−http :: Text -> Url 'Http
678+http :: T.Text -> Url 'Http
668http = Url Http . pure
679http = Url Http . pure
670-- | Given host name, produce a 'Url' which have “https” as its scheme and
681-- | Given host name, produce a 'Url' which have “https” as its scheme and
671-- empty path. This also sets port to @443@.
682-- empty path. This also sets port to @443@.
673−https :: Text -> Url 'Https
684+https :: T.Text -> Url 'Https
674https = Url Https . pure
685https = Url Https . pure
676-- | Grow given 'Url' appending a single path segment to it. Note that the
687-- | Grow given 'Url' appending a single path segment to it. Note that the
@@ -684,7 +695,7 @@ Url secure path /~ segment = Url secure (NE.cons (toUrlPiece segment) path)
684-- next URL piece is a 'Text' literal.
695-- next URL piece is a 'Text' literal.
686infixl 5 /:
697infixl 5 /:
687−(/:) :: Url scheme -> Text -> Url scheme
698+(/:) :: Url scheme -> T.Text -> Url scheme
688(/:) = (/~)
699(/:) = (/~)
690-- | The 'parseUrlHttp' function provides an alternative method to get 'Url'
701-- | The 'parseUrlHttp' function provides an alternative method to get 'Url'
@@ -715,7 +726,7 @@ parseUrlHttps url' = do
715-- | Get host\/collection of path pieces and possibly query parameters
726-- | Get host\/collection of path pieces and possibly query parameters
716-- already converted to 'Option'. This function is not public.
727-- already converted to 'Option'. This function is not public.
718−parseUrlHelper :: ByteString -> Maybe (NonEmpty Text, Option scheme)
729+parseUrlHelper :: ByteString -> Maybe (NonEmpty T.Text, Option scheme)
719parseUrlHelper url = do
730parseUrlHelper url = do
720 let (path', query') = B.break (== 0x3f) url
731 let (path', query') = B.break (== 0x3f) url
721 query = mconcat (uncurry queryParam <$> Y.parseQueryText query')
732 query = mconcat (uncurry queryParam <$> Y.parseQueryText query')
@@ -819,7 +830,7 @@ instance HttpBody ReqBodyUrlEnc where
819-- | An opaque monoidal value that allows to collect URL-encoded parameters
830-- | An opaque monoidal value that allows to collect URL-encoded parameters
820-- to be wrapped in 'ReqBodyUrlEnc'.
831-- to be wrapped in 'ReqBodyUrlEnc'.
822−newtype FormUrlEncodedParam = FormUrlEncodedParam [(Text, Maybe Text)]
833+newtype FormUrlEncodedParam = FormUrlEncodedParam [(T.Text, Maybe T.Text)]
823 deriving (Semigroup, Monoid)
834 deriving (Semigroup, Monoid)
825instance QueryParam FormUrlEncodedParam where
836instance QueryParam FormUrlEncodedParam where
@@ -852,6 +863,23 @@ type family ProvidesBody body :: CanHaveBody where
852 ProvidesBody NoReqBody = 'NoBody
863 ProvidesBody NoReqBody = 'NoBody
853 ProvidesBody body = 'CanHaveBody
864 ProvidesBody body = 'CanHaveBody
866+-- | This type function allows any HTTP body if method says it
867+-- 'CanHaveBody'. When method says it should have 'NoBody', the only body
868+-- option to use is 'NoReqBody'.
870+-- __Note__: users of GHC 8.0.1 will see slightly more friendly error
871+-- messages when method does not allow a body and body is provided.
873+type family HttpBodyAllowed
874+ (allowsBody :: CanHaveBody)
875+ (providesBody :: CanHaveBody) :: Constraint where
876+ HttpBodyAllowed 'NoBody 'NoBody = ()
877+ HttpBodyAllowed 'CanHaveBody body = ()
878+#if MIN_VERSION_base(4,9,0)
879+ HttpBodyAllowed 'NoBody 'CanHaveBody = TypeError
880+ ('Text "This HTTP method does not allow attaching a request body.")
855instance HttpBody body => RequestComponent (Womb "body" body) where
883instance HttpBody body => RequestComponent (Womb "body" body) where
856 getRequestMod (Womb body) = Endo $ \x ->
884 getRequestMod (Womb body) = Endo $ \x ->
857 x { L.requestBody = getRequestBody body
885 x { L.requestBody = getRequestBody body
@@ -935,7 +963,7 @@ instance RequestComponent (Option scheme) where
935-- > name =: value = queryParam name (pure value)
963-- > name =: value = queryParam name (pure value)
937infix 7 =:
965infix 7 =:
938−(=:) :: (QueryParam param, ToHttpApiData a) => Text -> a -> param
966+(=:) :: (QueryParam param, ToHttpApiData a) => T.Text -> a -> param
939name =: value = queryParam name (pure value)
967name =: value = queryParam name (pure value)
941-- | Construct a flag, that is, valueless query parameter. For example, in
969-- | Construct a flag, that is, valueless query parameter. For example, in
@@ -947,7 +975,7 @@ name =: value = queryParam name (pure value)
948-- > queryFlag name = queryParam name Nothing
976-- > queryFlag name = queryParam name Nothing
950−queryFlag :: QueryParam param => Text -> param
978+queryFlag :: QueryParam param => T.Text -> param
951queryFlag name = queryParam name (Nothing :: Maybe ())
979queryFlag name = queryParam name (Nothing :: Maybe ())
953-- | A type class for query-parameter-like things. The reason to have
981-- | A type class for query-parameter-like things. The reason to have
@@ -962,7 +990,7 @@ class QueryParam param where
962 -- way). It's recommended to use @('=:')@ and 'queryFlag' instead of this
990 -- way). It's recommended to use @('=:')@ and 'queryFlag' instead of this
963 -- method, because they are easier to read.
991 -- method, because they are easier to read.
965− queryParam :: ToHttpApiData a => Text -> Maybe a -> param
993+ queryParam :: ToHttpApiData a => T.Text -> Maybe a -> param
967instance QueryParam (Option scheme) where
995instance QueryParam (Option scheme) where
968 queryParam name mvalue =
996 queryParam name mvalue =