0

I am trying to run my webapp that is based on http4s on jetty. The http4s library provides AsyncHttp4sServlet[IO] class to extend and I use as follows:

class UserSvcServlet
    extends AsyncHttp4sServlet[IO](
      service = UserSvcServer.start,
      servletIo = BlockingServletIo(4096, Blocker.liftExecutorService(Executors.newCachedThreadPool())),
      serviceErrorHandler = DefaultServiceErrorHandler
    )

As you can see on the service property, I provide my http service that has the following implementation:

def start[F[_]: ConcurrentEffect: ContextShift: Sync: Timer]: HttpApp[F] =
for {

  a <- EnvironmentLoader.db.load[F].map(create_transactor)
  b <- EnvironmentLoader.cors.load[F].map(origin)
       http = Logger.httpApp(true, true)(CORS(UserRoutes(UserProgram(LiveUserQuery.make(a))).routes, b).orNotFound)
} yield http

The start method should return HttpApp[F] but unfortunately the for block returns F[Http[F]]. However at the end the F will be an IO type.

Here is the definition of HttpApp[F]:

type Http[F[_], G[_]] = Kleisli[F, Request[G], Response[G]]  

The both EnvironmentLoader.db.load[F].map(create_transactor) and EnvironmentLoader.cors.load[F].map(origin) is in the context of F and they load environment variables. For loading environment variables, I use the library https://cir.is/.

I know, it is not possible to get Http[F] out of the context F. Do I have here to restructure the code to make it work?

Update

One possible workaround would be:

class UserSvcServlet
    extends AsyncHttp4sServlet[IO](
      service = UserSvcServer.start[IO].unsafeRunSync(),
      servletIo = BlockingServletIo(4096, Blocker.liftExecutorService(Executors.newCachedThreadPool())),
      serviceErrorHandler = DefaultServiceErrorHandler
    )

It is ugly but it works.

softshipper
  • 32,463
  • 51
  • 192
  • 400

1 Answers1

4

Yes, you have to.

When you have F[Http[F]] you are supposed to compose it into your IO program:

for {
  dep1 <- createDependency1
  dep1 <- createDependency2
  http <- createHttp // : F[HttpApp[F]] = F[Request[F] => F[Response[F]]]
                     // or "use side effects to create a function that
                     // will take side-effecting request to create
                     // recipe for side-effecting response" (e.g.
                     // reading from stream to server and returning
                     // a stream from server)
  dep4 =  needHttp(http)
  ...
} yield ...

In your code a change from F[HttpApp[F]] to HttpApp[F] seems to literally require just changing:

http = ...

into

http <- ...

which kind of suggest, that you are not paying enough attention to what your code does.

Mateusz Kubuszok
  • 24,995
  • 4
  • 42
  • 64