1

Let's say I define this route using Akka Http:

  • POST method
  • If there's a specific header in the request I will remove it but I will add a new header with the same value (it is like I'm replacing a header in the request). I'm using a custom directive here.
  • Extract the body as a case class (SomeData)
  • Finally inside the complete block I have some code that uses the request (with the headers processed in step 2)

It would be something like this:

  val someRoute = replaceHeaders {
      post {
        extractRequest { req =>
          entity(as[SomeData]) { someData =>
            complete {
              // some code here that uses `req` (defined 3 lines above)
            }
          }
        }
      }
    }

For replacing headers I can define a custom directive, similar to this:

  def replaceHeaders: Directive0 =
    mapRequest(req =>
      req.headers.find(_.is(headerToReplace)) match {
          case Some(header) =>
            req
              .removeHeader(...)
              .addHeader(...(header.value()))
          case None => req
      }
    )

In the first code inside the complete block I have access to the request, in particular I have access to the headers that has been processed by replaceHeaders directive.

How can I do the same using http4s library? Because there are no customized directive as in Akka Http. I know I can create a function to do something similar:

  def replaceHeaders(request: Request[IO]): Headers = {
    val searchHeader = "SomeHeader"
    val newHeader = "NewHeader"

    request.headers.get(CaseInsensitiveString(searchHeader)) match {
      case Some(headerFound) =>
        request.headers
          .filterNot(_.name == CaseInsensitiveString(searchHeader))
          .put(Header(newHeader, headerFound.value))
      case None =>
        request.headers
    }
  }

  val routes: HttpRoutes[IO] = {
    val dsl = Http4sDsl[IO]
    import dsl._

    HttpRoutes.of[IO] {
      case req @ POST -> Root =>
        // replace one header for another
        val newHeaders = replaceHeaders(req)

        IO {
          Response[IO](Status.Ok)
            .withHeaders(newHeaders)
            .withEntity[String]("Process ok.")
        }

    }
  }

But in this case I have a new collection of headers: val newHeaders = replaceHeaders(req). But Akka Http is more flexible, when I make changes to the headers these are immediately available as part of the request after extractRequest. Every block after extractRequest when accessing the request will have the headers updated. But in the case of http4s (at least in my code) I have to explicitly use newHeaders to access the new headers.

How can I do the same in http4s?

M.G.
  • 369
  • 1
  • 14

0 Answers0