Http-tower-hs — A Rust Tower-inspired middleware library for Haskell
Haskell Community [Unofficial]
April 7, 2026
Here’s some rewrites of your example from OP, edited:
import Data.Functor ((<&>)) -- (<&>) = flip (<$>), like how (&) = flip ($)
client <- newClient
<&> withBearerAuth "my-token"
. withRequestId
. withRetry (exponentialBackoff 3 0.5 2.0)
. withTimeout 5000
. withCircuitBreaker config breaker
. withValidateStatus (\c -> c >= 200 && c < 300)
. withTracing
import Data.Function ((&))
client <- newClient
let configured = client
& withBearerAuth "my-token"
& withRequestId
& withRetry (exponentialBackoff 3 0.5 2.0)
& withTimeout 5000
& withCircuitBreaker config breaker
& withValidateStatus (\c -> c >= 200 && c < 300)
& withTracing
By the way, it might also be useful to give your Service type a Functor instance (can be derived automatically) and a Profunctor instance. If someone was writing a binding to a remote HTTP API, it’d provide a good way to lift a Service Http.Request Http.Response into a Service MyBinding.SomeRequest MyBinding.SomeResponse.
Discussion in the ATmosphere