Hi all,
I’d like to use this little http4s middleware http4s-session.
It requires session routes, which is essentially an alias for context routes with a ContextResponse instead of a regular Response.
So, I am able to create context routes with the contextIn method, but is there any way to “set” the context, something like a contextOut method, which I could then slap onto the context parameter of the ContextResponse along with the actual response?
I assume you’d like to somehow integrate with tapir’s endpoints?
I don’t think there’s a straightforward way: firstly, anything that’s read by the session middleware would be managed externally to tapir, so the documentation generated for the tapir endpoints would be incomplete (it would miss the authorization headers etc.). Similarly for the response - if there are some headers added, the wouldn’t be present in the docs.
It would be possible to write your own Http4sSessionServerInterpreter, which is of course feasible, but also not entirely trivial. So the short answer is that no, this is not possible OOTB.
You can implement this partially. In the tapir endpoints, you can use extractFromRequest to extract values from the underlying org.http4s.Request, which has an attribute map (where you can earlier set the authorization info). So given the HttpRoutes from the http4s interpreter, you could use them inside the session middleware, by first enriching the http4s request with the appropriate attributes (data read from the session).
Manipulating the response is harder, as you’d need to somehow extract the values returned by the endpoint and map them to the response. Probably it’s easier to just include this in the endpoint’s description.
Longer-term, maybe you could share what kind of functionality you are missing? Maybe it’s something we can provide on the tapir level, so that using a middleware wouldn’t be necessary in the first place.
To answer your last point, the functionality I’m looking for is simple session management. Now, I don’t think that’s a concern for tapir necessarily, but maybe a high level way of getting and setting session information would be nice?
When I thought of http4s and session, I naturally just reached for the http4s-session library, because I thought maintaining my own session state correctly might be tricky
Ah that’s what you meant. I intend to store a session cookie on the client, with just the session ID, and then co-relate that to a session in the session store.
And sure, I’ll do write that issue up, hopefully i’ll get a nice writeup cheers, happy new year!
So, I think I’ve found a decent solution. I realized that instead of relying on the SessionRoutes, I can just use the SessionStore by the package directly. That way, I can also make it integrate well enough with tapir, since all tapir needs to know about is the cookie part of the process, which it already has great support for, as you showed in the example you linked.
And then I just added two convenience input mappers
def sessionInfo(name: String) = extractFromRequest { r =>
val req = r.underlying.asInstanceOf[Request[IO]]
SessionIdentifier.extract(req, name).get
}
def sessionInfoOpt(name: String) = extractFromRequest { r =>
val req = r.underlying.asInstanceOf[Request[IO]]
SessionIdentifier.extract(req, name).get
}
I’ll try to see how far this design can go, and how well I can make it work
PS: Since this relies on http4s-session being in your shared project, which you may not want (maybe you don’t want these deps in your Scala.js bundle), one can also go about this with just extracting a cookie and then wrapping your cookie in a SessionIdentifier in the server logic