http4s: Composing Routes, Middleware & When It Fits
Combining Routes
val allRoutes = userRoutes <+> orderRoutes <+> healthRoutes
// Combines multiple HttpRoutes[F] values into one,
// trying each in turn until one matches the requestMiddleware
val loggedRoutes = Logger.httpRoutes(logHeaders = true, logBody = false)(userRoutes)
// Middleware functionally transforms one HttpRoutes[F] into
// another, wrapping it with additional behaviorEffect-Based Error Handling
Because IO has its own built-in error channel, error handling flows through that same mechanism -- keeping it consistent with the library's overall functional approach, rather than mixing in imperative try/catch.
Backend-Agnostic
http4s's core abstractions (routes, requests, responses) are defined independently of any specific server implementation, so applications can run on different underlying backends (ember, blaze) with relatively little application-level code change.
The Trade-off: Learning Curve
For developers unfamiliar with functional idioms (effect types, for-comprehensions over effects, type classes), http4s's style can mean a steeper initial learning curve than a more conventional imperative framework -- exchanged for stronger compositional and type-safety guarantees as complex request-handling logic grows.
Keep your own version of these notes — editable, searchable, and organised by your stack.
Start free