Core functionality and class for client function generation for servant APIs

Version on this page:0.18.3
LTS Haskell 22.17:0.20@rev:3
Stackage Nightly 2024-04-17:0.20@rev:3
Latest on Hackage:0.20@rev:3

See all snapshots servant-client-core appears in

BSD-3-Clause licensed by Servant Contributors
Maintained by [email protected]
This version can be pinned in stack with:servant-client-core-0.18.3@sha256:db2551c94cc17bef7682602082d6a16e79593cfc939f2d696d4ccee21b2b2091,3649



HTTP-client-agnostic client functions for servant APIs.

This library should mainly be of interest to backend- and combinator-writers.

For backend-writers

If you are creating a new backend, you’ll need to:

  1. Define a RunClient instance for your datatype (call it MyMonad)
  2. Define a ClientLike instance. This will look like:
instance ClientLike (MyMonad a) (MyMonad a) where
  mkClient = id
  1. Re-export the module Servant.Client.Core.Reexport so that your end-users can be blissfully unaware of ‘servant-client-core’, and so each backend-package comes closer to the warm hearth of the drop-in-replacement equivalence class.

For combinator-writers

You’ll need to define a new HasClient instance for your combinator. There are plenty of examples to guide you in the HasClient module.


The latest version of this document is on GitHub. Changelog for servant package contains significant entries for all core packages.


Significant changes

  • Add response header support to UVerb (#1420)

Other changes

  • Support GHC-9.0.1.
  • Bump bytestring, hspec, base64-bytestring and QuickCheck dependencies.


Significant changes

  • Support Fragment combinator.


Significant changes

  • Union verbs

Other changes

  • Bump “tested-with” ghc versions
  • Loosen bound on base16-bytestring


Significant changes

  • Support for ghc8.8 (#1318, #1326, #1327)


Significant changes

  • Add NoContentVerb #1028 #1219 #1228

    The NoContent API endpoints should now use NoContentVerb combinator. The API type changes are usually of the kind

    - :<|> PostNoContent '[JSON] NoContent
    + :<|> PostNoContent

    i.e. one doesn’t need to specify the content-type anymore. There is no content.

  • Capture can be Lenient #1155 #1156

    You can specify a lenient capture as

    :<|> "capture-lenient"  :> Capture' '[Lenient] "foo" Int :> GET

    which will make the capture always succeed. Handlers will be of the type Either String CapturedType, where Left err represents the possible parse failure.

Other changes

  • servant-client servant-client-core servant-http-streams Fix Verb with headers checking content type differently #1200 #1204

    For Verbs with response Headers, the implementation didn’t check for the content-type of the response. Now it does.

  • servant-client servant-http-streams HasClient instance for Stream with Headers #1170 #1197

  • servant-client Redact the authorization header in Show and exceptions #1238


  • Rename ServantError to ClientError, ServantErr to ServerError #1131

  • servant-client-core Rearrange modules. No more Internal modules, whole API is versioned. #1130

  • servant-client-core RequestBody is now

    = RequestBodyLBS LBS.ByteString
    | RequestBodyBS BS.ByteString
    | RequestBodySource (SourceIO LBS.ByteString)

    i.e. no more replicates http-clients API. #1117

  • servant-client-core Keep structured exceptions in ConnectionError constructor of ClientError #1115

    -| ConnectionError Text
    +| ConnectionError SomeException
  • servant-client-core Preserve failing request in FailureResponse constructor of ClientError #1114

    -FailureResponse Response
    +-- | The server returned an error response including the
    +-- failing request. 'requestPath' includes the 'BaseUrl' and the
    +-- path of the request.
    +FailureResponse (RequestF () (BaseUrl, BS.ByteString)) Response
  • servant-client Fix (implement) StreamBody instance #1110

  • servant-client Update CookieJar with intermediate request/responses (redirects) #1104


  • Streaming refactoring. #991 #1076 #1077

    The streaming functionality (Servant.API.Stream) is refactored to use servant’s own SourceIO type (see Servant.Types.SourceT documentation), which replaces both StreamGenerator and ResultStream types.

    New conversion type-classes are ToSourceIO and FromSourceIO (replacing ToStreamGenerator and BuildFromStream). There are instances for conduit, pipes and machines in new packages: servant-conduit servant-pipes and servant-machines respectively.

    Writing new framing strategies is simpler. Check existing strategies for examples.

    This change shouldn’t affect you, if you don’t use streaming endpoints.

  • servant-client Separate streaming client. #1066

    We now have two http-client based clients, in Servant.Client and Servant.Client.Streaming.

    Their API is the same, except for

    • Servant.Client cannot request Stream endpoints.
    • Servant.Client is run by direct runClientM :: ClientM a -> ClientEnv -> IO (Either ServantError a)
    • Servant.Client.Streaming can request Stream endpoints.
    • Servant.Client.Streaming is used by CPSised withClientM :: ClientM a -> ClientEnv -> (Either ServantError a -> IO b) -> IO b

    To access Stream endpoints use Servant.Client.Streaming with withClientM; otherwise you can continue using Servant.Client with runClientM. You can use both too, ClientEnv and BaseUrl types are same for both.

    Note: Servant.Client.Streaming doesn’t stream non-Stream endpoints. Requesting ordinary Verb endpoints (e.g. Get) will block until the whole response is received.

    There is Servant.Client.Streaming.runClientM function, but it has restricted type. NFData a constraint prevents using it with SourceT, Conduit etc. response types.

    runClientM :: NFData a => ClientM a -> ClientEnv -> IO (Either ServantError a)

    This change shouldn’t affect you, if you don’t use streaming endpoints.

  • servant-client-core Related to the previous: streamingResponse is removed from RunClient. We have a new type-class:

    class RunClient m =>  RunStreamingClient m where
        withStreamingRequest :: Request -> (StreamingResponse -> IO a) ->  m a
  • Drop support for GHC older than 8.0 #1008 #1009

  • servant-client-core Add NFData (GenResponse a) and NFData ServantError instances. #1076

  • servant-client-core Add aeson and Lift BaseUrl instances #1037


  • Merge in servant-generic (by Patrick Chilton) into servant (Servant.API.Generic), servant-client-code (Servant.Client.Generic) and servant-server (Servant.Server.Generic).


  • Stream takes a status code argument

    -Stream method        framing ctype a
    +Stream method status framing ctype a

    (#966 #972)

  • ToStreamGenerator definition changed, so it’s possible to write an instance for conduits.

    -class ToStreamGenerator f a where
    -   toStreamGenerator :: f a -> StreamGenerator a
    +class ToStreamGenerator a b | a -> b where
    +   toStreamGenerator :: a -> StreamGenerator b


  • Added NoFraming streaming strategy (#959)

  • servant-client-core Free Client implementation. Useful for testing HasClient instances. (#920)

  • servant-client-core Add hoistClient to HasClient. Just like hoistServer allows us to change the monad in which request handlers of a web application live, we also have hoistClient for changing the monad in which client functions live. Read tutorial section for more information. (#936)

    iF you have own combinators, you’ll need to define a new method of HasClient class, for example:

    type Client m (MyCombinator :> api) = MyValue :> Client m api
    hoistClientMonad pm _ nt cl = hoistClientMonad pm (Proxy :: Proxy api) nt . cl

  • Support base-compat-0.10


  • Streaming endpoint support. (#836)
  • servant Add Servant.API.Modifiers (#873)


  • First version. Factored out of servant-client all the functionality that was independent of the http-client backend.