Skip to content

Middlewares

Middlewares are functions that take a handler as their input and produces a handler as output. They are useful to enhance behaviour of handlers.

type Middleware req req' a' a = Handler req' a' -> Handler req a

We already met the queryParam function in the previous section which is a middleware. Here is possible implementation for it in pseudo-code:

queryParam :: (KnownSymbol name, FromHttpApiData val)
           => Middleware req (QueryParam name val:req) a a
queryParam handler = Kleisli $ \request -> do
  res <- probe @(QueryParam name val) request
  either sendErrorResponse (runKleisli handler) res

As you can see, this just uses probe as mentioned in the previous section in an attempt to prove the presence of the QueryParam trait. If successful, we call handler with that result and if unsuccessful, use sendErrorResponse to handle it.

Types of Middlewares

So what are the kind of things we can do in a middleware?

As seen in the queryParam example, we can modify the request parameter passed to the inner handler. Such middlewares are called request middlewares and have this type:

type RequestMiddleware req req' a = Middleware req req' a a

Similarly, we have response middlewares which modify the responses sent from the inner handler.

type ResponseMiddleware req a' a = Middleware req req a' a

Of course, we could have a middleware that modifies both the request and response.