http4s / http4s

A minimal, idiomatic Scala interface for HTTP
https://http4s.org/
Apache License 2.0
2.56k stars 789 forks source link

Missing easier way to decode base64 Body #4976

Open tiphdousset opened 3 years ago

tiphdousset commented 3 years ago

Hi there,

I have the following situation: to preserve the integrity of binary responses the APIGateway of my project is encoding the body of the requests with base64. My service needs then to first decode the body before being able to use it. The only way I found so far is quite "heavy" and it would be great if http4s would have his own decodeBase64 method.

import io.circe.parser.
import java.util.Base64
import java.nio.charset.StandardCharsets
import org.http4s.EntityDecoder
import java.nio.ByteBuffer
import org.http4s.MediaType
import org.http4s.DecodeFailure
import org.http4s.DecodeResult
import io.circe

 def decodeBase64(encoded: Array[Byte]): String = {
    val bytes: Array[Byte] = Base64.getDecoder().decode(encoded)
    new String(bytes, StandardCharsets.UTF_8)
  }

  val requestDecoder =
    EntityDecoder.decodeBy[F, ByteBuffer](MediaType.application.`octet-stream`) {
      m =>
        EntityDecoder
          .collectBinary(m)
          .map(chunk => ByteBuffer.wrap(chunk.toArray))
    }

  def decodeBody(req: Request[F]): F[Either[String, Body]] = {
    val decodedRequest = requestDecoder.decode(req, strict = false)
    decodedRequest.value.map {
      case Right(bytes: ByteBuffer) => {
        val bodyString: String = decodeBase64(bytes.array())
        println("Body as String: " + bodyString)
        val bodyEither = decode[Body](bodyString)
        bodyEither.leftMap[String](e => "Error while decoding body")
      }
      case Left(_) => Left("Error while decoding body")
    }
  }

*Body is a simple case class of my project

rossabaker commented 3 years ago

Instead of decodeBase64 taking an Array[Byte], we might consider adding a combinator for EntityDecoder that first decodes the stream via base64 before passing the decoded stream to another decoder. Then we could take advantage of fs2's streaming base64 support.