Your Location is: Home > Scala

Akka http: how to make complete function see my Encoders?

From: Peru View: 4663 Dmitry Reutov 

Question

I have a couple of case classes and made encoders for them

trait appJSONProtocol extends DefaultJsonProtocol {
  implicit val jsCat = jsonFormat4(Category)
  implicit val jsCatRel = jsonFormat3(CategoryRel)

  implicit val encodeCat: Encoder[Category] =
    Encoder.forProduct4("id", "name", "parentId", "level")(u =>
      (u.id, u.name, u.parentId, u.level)
    )

  implicit val encodeCatRel: Encoder[CategoryRel] =
    Encoder.forProduct6("id", "name", "parentId", "level", "parentOfMine", "children")(u =>
      (u.category.id, u.category.name, u.category.parentId, u.category.level, u.parent, u.children)
    )
}

now i want to make response according these encoders

def completeTask[T] (task: Future[T])(
    implicit encoder: Encoder[T],
    m: ToEntityMarshaller[T]
  ) = {
    onComplete(task) {
      case Success(data) => {
        println(data.asJson)
        complete(OK, data)
      }
      case Failure(throwable) =>
        complete(BadRequest, throwable.getMessage)
    }
  }

data.asJson works perfectly well, but complete function returns json as it does not see my encoders. It seems like it expects some EntityMarshaller parameter, but how and where can i apply Encoder then?

Best answer

Finally this implicit function helped to translate my encoders to ToEntityMarshaller type

implicit final def marshaller[A: Encoder]: ToEntityMarshaller[A] = {
    Marshaller.withFixedContentType(`application/json`) { a =>
      HttpEntity(`application/json`, a.asJson.noSpaces)
    }
  }

Another answer

While your solution works, there's not really a reason to write this yourself. There's an implementation in a library:

https://doc.akka.io/docs/akka-http/current/common/json-support.html

Mix in the akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport trait and you're done.