scalazio-http

How to get a value of HandlerAspect's `CtxOut` type in request processing


In zio-http, one has the option to write middleware that provide some sort of context around a request; as a concrete example, we might think of an auth middleware that looks up some package of session information before processing a request:

case class UserSession(sessionId: UUID, username: String)

val authMiddleware: HandlerAspect[Any, UserSession] = HandlerAspect.customAuthProvidingZIO {  request =>
  ZIO.succeed(request.headers.get("X-Session-ID").flatMap {
    case None => ZIO.succeed(None)
    case Some(sessionId) => fetchSession(sessionId).catchAll(_ => ZIO.succeed(None))
  }
}

We can attach this middleware to a Routes to ensure that any request coming in with no X-Session-ID header, or a session ID that our session cache doesn't know about, gets rejected. My question is, if the middleware succeeds in producing a UserSession, how can I get that value and use it in the request handler, something like

// this doesn't work
Routes(
  Method.GET / "foo" -> handler { (userSession: UserSession, request: Request) =>
    fooDatabase.getAll(userSession.username)
  }
) @@ authMiddleware

One reason this doesn't work, of course, is that the middleware isn't even attached to the Routes until after it's created, so there's something of a chicken-and-egg problem; but that seems to be kinda the point of middleware, and this GitHub issue and this PR have titles at least that suggest that they're trying to achieve something similar to this, though I don't see anything exactly like what I'm looking for in the PR code.


Solution

  • Instead of attaching the middleware/HandlerAspect to the "outside" of the Routes as in the snippet in the question, it turns out that it's possible to reference the middleware in the definition of each Route itself:

    val authMiddleware: HandlerAspect[Any, UserSession] = ???
    Routes(
      Method.GET / "foo" -> authMiddleware -> handler { (userSession: UserSession, request: Request) =>
        ...business logic goes here... }
    )
    

    (Kudos to user zzyzzyxx on the ZIO Discord for this find.)