1

I have a wai middleware that produces two values:

  1. A request id generated randomly for each request
  2. A User from a request to another service.

Here is the code:

addRequestIdToRequestHeader' :: Application -> Application
addRequestIdToRequestHeader' app req respond = do
  rid <- nextRequestId :: IO ByteString
  user <- fetchUserByReq req :: IO User
  req' <- attachUserAndRequestIdToRequest user rid
  app req' respond

Now I have a route GET /user. Inside of this route, I’d like to have access to the request id and the User. As an example, I might just print them in the log.

main :: IO ()
main =
  scotty 8080 $ do
    get "/user" $ do
      req <- request
      rid <- liftAndCatchIO $ getRequestIdFromRequest req
      user <- liftAndCatchIO $ getUserFromRequest req
      liftAndCatchIO $ print rid
      liftAndCatchIO $ print user
      text $ username user

The question is since the request id and the User are generated from the middleware, how to access them from the route? Basically how to implement the following functions used in the above code:

attachUserAndRequestIdToRequest :: User -> ByteString -> Request -> IO Request

getRequestIdFromRequest :: Request -> IO ByteString

getUserFromRequest :: Request -> IO User

The scenario is the middleware is an Auth middleware, which forwards the request to another service for authentication and gets back the user value, which will be needed in the routes.

Leo Zhang
  • 3,040
  • 3
  • 24
  • 38
  • Did you look on WAI's vault: https://www.yesodweb.com/blog/2015/10/using-wais-vault ? – Sibi Sep 14 '18 at 03:18
  • I did. But I’m not sure if each request shares the same vault or different. If it’s the same vault, then it doesn’t work for me. My understanding is that the examples in that blog post generate a global random key to store a single random data. If a new request comes, the data stored under that global key will be overwritten, this is not I wanted. The data stored in vault has the same lifecycle as the application, whereas what I wanted is to let the data have the same lifecycle as the Request so that I don’t need to remember to delete them at he end of each request. – Leo Zhang Sep 14 '18 at 10:23
  • Hi @michael-snoyman, Can I get some advice from you? – Leo Zhang Sep 18 '18 at 23:21
  • Just thinking out loudly: Can't you add that data in the header in one of the middleware and then retrieve them in the Yesod handlers and discard them ? – Sibi Sep 19 '18 at 02:13
  • Thanks @Sibi. It works for the Request Id which is ByteString. But doesn’t work for User, which is my own data type. Header value only supports Bytestring – Leo Zhang Sep 19 '18 at 02:24
  • Can't you serialize User into ByteString ? – Sibi Sep 19 '18 at 02:33
  • Since User likely has a `Show` instance, convert into `String` and then into `ByteString`. You also need to deserialize it properly. – Sibi Sep 19 '18 at 02:34
  • Yeah, that’s a workaround if User is has a Show and Read instance. Thanks for giving the idea. I wonder if possible to achieve without this serialization and deserialization overhead. – Leo Zhang Sep 19 '18 at 04:37

0 Answers0