I'm trying to unmarshall request payload as string, but for some reason it's failing. My code:
path("mypath") {
post {
decodeRequest {
entity(as[String]) {jsonStr => //could not find implicit value for...FromRequestUnmarshaller[String]
complete {
val json: JsObject = Json.parse(jsonStr).as[JsObject]
val jsObjectFuture: Future[JsObject] = MyDatabase.addListItem(json)
jsObjectFuture.map(_.as[String])
}
}
}
}
}
In this SO thread for example it seems to be that this implicit should be available by default. But maybe this is different in akka-http?
I tried importing akka.http.scaladsl.unmarshalling.PredefinedFromEntityUnmarshallers
which has a stringUnmarshaller
but it doesn't help. Maybe because this returns type FromEntityUnmarshaller[String]
not FromRequestUnmarshaller[String]
. There's also a string unmarshaller in spray.httpx.unmarshalling.BasicUnmarshallers
but this also doesn't help, neither akka.http.scaladsl.unmarshalling.PredefinedFromStringUnmarshallers
How can I unmarshall (and marshall) into a string?
(Bonus: How to unmarshall directly in a JsObject (play json). But also only string as I'm interested in why this is not working and it may be useful for other cases).
Using 1.0-RC3
Thanks.
Your code should be okay provided you have the right implicits in scope. If you have an implicit FlowMaterializer
in scope then things should work as expected as this code that compiles shows:
import akka.http.scaladsl.server.Route
import akka.actor.ActorSystem
import akka.stream.ActorFlowMaterializer
import akka.http.scaladsl.model.StatusCodes._
import akka.http.scaladsl.server.Directives._
import akka.stream.FlowMaterializer
implicit val system = ActorSystem("test")
implicit val mater = ActorFlowMaterializer()
val routes:Route = {
post{
decodeRequest{
entity(as[String]){ str =>
complete(OK, str)
}
}
}
}
If you wanted to take things a step further and unmarshall to a JsObject
then you just need an implicit Unmarshaller
in scope to handle that conversion, something like this:
implicit val system = ActorSystem("test")
implicit val mater = ActorFlowMaterializer()
import akka.http.scaladsl.unmarshalling.Unmarshaller
import akka.http.scaladsl.model.HttpEntity
implicit val um:Unmarshaller[HttpEntity, JsObject] = {
Unmarshaller.byteStringUnmarshaller.mapWithCharset { (data, charset) =>
Json.parse(data.toArray).as[JsObject]
}
}
val routes:Route = {
post{
decodeRequest{
entity(as[String]){ str =>
complete(OK, str)
}
}
} ~
(post & path("/foo/baz") & entity(as[JsObject])){ baz =>
complete(OK, baz.toString)
}
}