3

I'm trying to share state between multiple http requests on http4s server.

That is what I tried:

for {
     state  <- Ref[F].of(0)
 
    _ <- BlazeServerBuilder[F]
         .bindHttp(port, host)
         .withHttpApp( ... httpApp that has link to "state" ... )
         .serve.compile.lastOrError

} yield  () 

The state remains the same after I change it inside http request.

Is it possible to share "state" in a pure FP style using Ref or something from Fs2?

UPDATE: the problem was inside my app. not related to how I pass the Ref. my bad.

Bogdan Vakulenko
  • 3,380
  • 1
  • 10
  • 25

1 Answers1

5

You can modify state just fine inside an HTTP request. Side effects are the whole point of the IO monad, and mutable state is what Ref is for. Here's an example of a route that will count the number of times it has been called:

  def countRoutes[F[_]: Defer: Monad](ref: Ref[F, Int]): HttpRoutes[F] = {
    val dsl = new Http4sDsl[F]{}
    import dsl._
    HttpRoutes.of[F] {
      case GET -> Root / "count" =>
        for {
          current  <- ref.updateAndGet(_ + 1)
          resp <- Ok(current.toString)
        } yield resp
    }
  }

Your initialization code looks weird though. It should be something like this:

for {
    state  <- Ref[IO].of(0)
    exitCode <- BlazeServerBuilder[F]
           .bindHttp(port, host)
           .withHttpApp( ... httpApp that has link to "state" ... )
           .serve.compile.lastOrError
} yield exitCode
Matthias Berndt
  • 4,387
  • 1
  • 11
  • 25
  • I faced almost the same problem. Is it possible to use `Ref` in case each request allocates some `Resource` which are then combined together to get freed? I mean something like `Ref[F, Resource[F, Unit]]` – Some Name Jul 05 '20 at 13:49