Middleware is a function that wraps a WAI Application, allowing a web server to inspect a request, produce a response, or delegate to the wrapped application. Since an Application receives a Request and response callback, Middleware has the shape Application -> Application. section 17.2.2 section 17.4
type Application = Request -> (Response -> IO ResponseReceived) -> IO ResponseReceived
Read the Application type as a request-handling function: it receives a request and a callback used to deliver the response. section 17.2.2
type Middleware = Application -> Application
The Middleware type makes wrapping explicit: provide an Application and return another Application. section 17.2.2
Adding an HTML root to a Servant API
A todo-list server can keep its typed Servant API unchanged while Middleware handles GET requests at /. The middleware checks requestMethod and pathInfo. For the root request, it loads and sorts todo entries, renders HTML as UTF-8, and calls responseLBS with a successful response and text/html content type. For every other request, it runs app req responseAct, preserving the API server's behavior. The server composes both layers with run port (mkAppRoot dbConn $ mkApiServer dbConn). section 17.2.2 section 17.2.3
Listing 17.10 A Middleware to render the todo list as HTML on the application’s root
mkAppRoot :: Connection -> Middleware
mkAppRoot dbConn app req responseAct
| isRootRequest = do
html <- rootHandler dbConn #1
responseAct $ responseLBS ok200 headers
(H.renderHtml html) #2
| otherwise = app req responseAct #3
where
headers = [(hContentType,
"text/html; charset=utf-8")] #4
isRootRequest =
requestMethod req == methodGet #5
&& null (pathInfo req) #5
Follow the complete middleware shape: handle the matching root request, construct the response, and delegate all other requests. section 17.2.3
When adding middleware, keep these practical points in view:
- Match narrowly: the example handles only GET requests whose path is the application root. section 17.2.2
- Delegate unmatched requests to the wrapped application so existing API endpoints continue to work. section 17.2.3
- Recognize the trade-off: modifying an Application this way loses the static guarantee that another GET / endpoint is not being intercepted. section 17.2.3









