content: -- | The 'RunClient' module provides a class which any client must instantiate in order to
  -- run HTTP requests.
  --
  {-# LANGUAGE DeriveFunctor #-}
  module Hreq.Core.Client.RunClient where
  
  import Hreq.Core.Client.ClientError
  import Hreq.Core.Client.Request
  import Hreq.Core.Client.Response
  
  -- | Provides the capability to run a request and get a response.
  class Monad m => RunClient m where
    runClient :: Request -> m Response
  
    throwHttpError :: ClientError -> m a
  
    checkResponse :: Request -> Response -> m (Maybe ClientError)
  
  class Monad m => RunStreamingClient m a where
    withStreamingClient
        :: forall r. Request
        -> (a -> IO r)
        -> m r
  
  -- * Pure client
  
  -- | A pure HTTP client monad useful for testing.
  data ClientPure (state :: k) a
      = RunClient Request a
      | Throw ClientError
    deriving (Functor, Show, Eq)
  
  instance Monad (ClientPure state)  where
    return = pure
  
    m >>= f = case m of
      RunClient r x -> setHttpRequest r $ f x
      Throw e     -> Throw e
  
  instance Applicative (ClientPure state) where
    pure = RunClient defaultRequest
  
    f <*> x = case x of
      Throw e     -> Throw e
      RunClient r y -> setHttpRequest r $ fmap ( $ y) f
  
  setHttpRequest :: Request -> ClientPure state a -> ClientPure state a
  setHttpRequest r h = case h of
    RunClient _ rs -> RunClient r rs
    Throw e      -> Throw e
  