1

Let me start by saying that i am very new to akka-http, none of the books i have covered the marsheling topic well. So it is bit of a blackbox for me. I was able to obtain the following (Un)Marsheller which is capable of returning both json and protobuf based on a request header.

This part of the code works fine and i have a get route defined in akka-http and it works fine.

trait PBMarshaller {

  private val protobufContentType = ContentType(MediaType.applicationBinary("octet-stream", Compressible, "proto"))
  private val applicationJsonContentType = ContentTypes.`application/json`


  implicit def PBFromRequestUnmarshaller[T <: GeneratedMessage with Message[T]](companion: GeneratedMessageCompanion[T]): FromEntityUnmarshaller[T] = {
    Unmarshaller.withMaterializer[HttpEntity, T](_ => implicit mat => {
      case entity@HttpEntity.Strict(`applicationJsonContentType`, data) =>
        val charBuffer = Unmarshaller.bestUnmarshallingCharsetFor(entity)
        FastFuture.successful(JsonFormat.fromJsonString(data.decodeString(charBuffer.nioCharset().name()))(companion))
      case entity@HttpEntity.Strict(`protobufContentType`, data) =>
        FastFuture.successful(companion.parseFrom(CodedInputStream.newInstance(data.asByteBuffer)))
      case entity =>
        Future.failed(UnsupportedContentTypeException(applicationJsonContentType, protobufContentType))
    })
  }

  implicit def PBToEntityMarshaller[T <: GeneratedMessage]: ToEntityMarshaller[T] = {
    def jsonMarshaller(): ToEntityMarshaller[T] = {
      val contentType = applicationJsonContentType
      Marshaller.withFixedContentType(contentType) { value =>
        HttpEntity(contentType, JsonFormat.toJsonString(value))
      }
    }

    def protobufMarshaller(): ToEntityMarshaller[T] = {
      Marshaller.withFixedContentType(protobufContentType) { value =>
        HttpEntity(protobufContentType, value.toByteArray)
      }
    }

    Marshaller.oneOf(protobufMarshaller(), jsonMarshaller())
  }

}

the issue i am facing is on the post route.

(post & entity(as[PropertyEntity])) { propertyEntity =>
          complete {
            saveProperty(propertyEntity)
          }
      }

During compilation time, i get the following error

Error:(20, 24) could not find implicit value for parameter um: akka.http.scaladsl.unmarshalling.FromRequestUnmarshaller[PropertyEntity]
      (post & entity(as[PropertyEntity])) { propertyEntity =>

I am not sure exactly what i am missing. Do i need to define an implicit FromRequestUnmarshaller ? if so what should it have?

DevZer0
  • 13,433
  • 7
  • 27
  • 51

1 Answers1

0

i was able to hack something together that works for the moment, but i still don't know how to create a general Unmarshaller that can decode any ScalaPB case class

implicit val um:Unmarshaller[HttpEntity, PropertyEntity] = {
    Unmarshaller.byteStringUnmarshaller.mapWithCharset { (data, charset) =>
        val charBuffer = Unmarshaller.bestUnmarshallingCharsetFor(data)
        JsonFormat.fromJsonString(data.decodeString(charBuffer.nioCharset().name()))(PropertyEntity)
        /*PropertyEntity.parseFrom(CodedInputStream.newInstance(data.asByteBuffer))*/
    }
  }

even this i don't know how to have both decoders enabled at the same time. so i have commented one out.

DevZer0
  • 13,433
  • 7
  • 27
  • 51