hseeberger/akka-http-json

Unmarshall gzipped responses

jhoncamargo opened this issue · 3 comments

Hi everyone, using this directive in routes

encodeResponseWith(Gzip) {
  ...
}

produce this error:
io.circe.ParsingFailure: expected json value got � (line 1, column 1)

when executing this line:
Unmarshal(httpResponse.entity).to[...]

This is because the response is encoded with gzip so it is an Array[Byte] and the Unmarshaller is expecting a ByteString

I could manage to overcome using this function to unzip the response:

/**
  * Unzip and return the String-JSON representation in this Array[Byte]
  */
def unzip(compressed: Array[Byte]): Either[Throwable, String] =
  Try {
    val inputStream = new GZIPInputStream(new ByteArrayInputStream(compressed))
    scala.io.Source.fromInputStream(inputStream).mkString
  }.toEither

And defining this Unmarshaller:

implicit def circeCompressUnMarshaller[A](implicit decoder: Decoder[A]): FromEntityUnmarshaller[A] =
    Unmarshaller.byteArrayUnmarshaller.map(
      unzip(_).flatMap(jawn.decode[A]).fold(throw _, identity)
    )

But I dont know if this is the right solution and it can be added to this repo.

Thank you @hseeberger

@jhoncamargo cool stuff: you know you Scala!

I think compression should not be a concern of this library which is only focussed on JSON. I also think that it's not a great idea to implicitly unzip stuff: that probably should happen explicitly.

Therefore I suggest to first wrap your route in a unzipping stage and then apply the usual unmarhalling magic. Does that make sense?

I didn't understand about the unzipping stage, my routes need to support Gzip compression so I can't remove that directive from them. Please can you provide some code example or links related to your suggestion?
Thank you

Never used that myself, sorry.