3

I want to implement an http4s server that receives the content from another service, processes it and return the response.

The original service uses redirects so I added the Follow redirect middleware. I also added the Logger middleware to check the logs produced.

The skeleton of the service is:

implicit val clientResource = BlazeClientBuilder[F](global).resource
val wikidataEntityUrl = "http://www.wikidata.org/entity/Q"

def routes(implicit timer: Timer[F]): HttpRoutes[F] = HttpRoutes.of[F] {
 case GET -> Root / "e" / entity => {
   val uri =  uri"http://www.wikidata.org/entity/" / ("Q" + entity)
   val req: Request[F] = Request(uri = uri)
   clientResource.use { c => {
     val req: Request[F] = Request(Method.GET, uri)
     def cb(resp: Response[F]): F[Response[F]] = Ok(resp.bodyAsText)
     val redirectClient = Logger(true,true,_ => false)(FollowRedirect[F](10, _ => true)(c))
     redirectClient.fetch[Response[F]](req)(cb)
 }}}}

When I try to access the service with curl as:

curl -v http://localhost:8080/e/33

The response contains the first part of the original content and finnishes with:

transfer closed with outstanding read data remaining
* Closing connection 0

Looking at the logs, they content the following line:

ERROR o.h.s.blaze.Http1ServerStage$$anon$1 - Error writing body
org.http4s.InvalidBodyException: Received premature EOF.

which suggests that there was an error receiving a premature EOF.

I found a possible answer in this issue: but the answers suggest to use deprecated methods like tohttpService.

I think I would need to rewrite the code using a streams, but I am not sure what's the more idiomatic way to do it. Some suggestions?

Labra
  • 1,412
  • 1
  • 13
  • 33

1 Answers1

3

I received some help in the http4s gitter channel to use the toHttpApp method instead of the fetch method.

I was also suggested also to pass the client as a parameter.

The resulting code is:

 case GET -> Root / "s" / entity => {
  val uri =  uri"http://www.wikidata.org/entity/" / ("Q" + entity)
  val req: Request[F] = Request(Method.GET, uri)
  val redirectClient = Logger(true,true,_ => false)(FollowRedirect[F](10, _ => true)(client))
  redirectClient.toHttpApp.run(req)
}

and now it works as expected.

The toHttpApp method is intended for use in proxy servers.

Labra
  • 1,412
  • 1
  • 13
  • 33