spray Collection ToResponseMarshallable
Asked Answered
T

3

6

I am trying to return a List from my complete directive in spray-routing.

complete {
  List("hello")
}

However, I am getting an error -

Expression of type List[String] doesn't conform to expected type ToResponseMarshallable

I am getting the same error with Seq. I see that marshallers for List and Seq are not provided by default in spray-httpx documentation. However, spray-json provides marshalling support in its DefaultJsonProtocol. I have imported spray.httpx.SprayJsonSupport._ and spray.json.DefaultJsonProtocol._ in my code, but that too hasn't helped.

Any idea how can I marshal a List/Seq using spray-json? Or will I have to write my own Marshaller?

(My scala version is 2.11.4)

Twopiece answered 18/2, 2015 at 2:43 Comment(0)
R
5

Using spray 1.3.2 and spray-json 1.3.2 it should be possible.

Make sure you import (although you say you do, but double check).

import spray.httpx.SprayJsonSupport._
import spray.json.DefaultJsonProtocol._

Consider following example:

import akka.actor.{ActorSystem, Props, Actor}
import akka.io.IO
import spray.can.Http
import spray.routing.HttpService
import akka.pattern.ask
import akka.util.Timeout
import scala.concurrent.duration._
import spray.httpx.SprayJsonSupport._
import spray.json.DefaultJsonProtocol._

object Boot extends App {
  implicit val system = ActorSystem("so")

  val testActor = system.actorOf(Props[TestActor])

  implicit val timeout = Timeout(5.seconds)
  IO(Http) ? Http.Bind(testActor, interface = "0.0.0.0", port = 5000)

}

class TestActor extends Actor with HttpService {

  def receive  = runRoute(route)

  def actorRefFactory = context

  val route = get{
    path("ping") {
      complete(List("OK"))
    }
  }

}

Requesting /ping returns ["OK"] which looks okay.

Just for reference build.sbt bellow.

build.sbt

val akkaVersion = "2.3.5"

val sprayVersion = "1.3.2"

resolvers += "spray" at "http://repo.spray.io/"

scalaVersion := "2.11.5"

scalacOptions := Seq("-feature", "-unchecked", "-deprecation", "-encoding", "utf8")

libraryDependencies ++= Seq(
  "com.typesafe.akka"   %% "akka-actor"       % akkaVersion,
  "io.spray"            %% "spray-can"        % sprayVersion,
  "io.spray"            %% "spray-routing"    % sprayVersion,
  "io.spray"            %% "spray-client"     % sprayVersion,
  "io.spray"            %% "spray-json"       % "1.3.1"
)
Roseola answered 19/2, 2015 at 11:40 Comment(3)
Yes this works. But if I replace the parentheses with braces, it fails. I'm doing complete{List("OK")}. My actual scenario requires a code block. Do you know why this might be failing with braces?Twopiece
When I replace ( with { and ) with } in my example it works, so are you sure this is the only change you made?Roseola
Okay. I think it's just IntelliJ which is going crazy. When I build and run my project, it works fine. Thanks!Twopiece
S
1

API for marshalling seems to have changed since akka 2.3.5. For akka-2.4.11.2, SprayJsonSupport needs import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._

1) Following is working sbt,

name := "some-project"

version := "1.0"

scalaVersion := "2.11.5"

scalacOptions := Seq("-unchecked", "-deprecation", "-encoding", "utf8")

val akkaVersion = "2.4.5"

libraryDependencies ++= {
  Seq(
    "com.typesafe.akka" %% "akka-http-experimental" % akkaVersion,
    "com.typesafe.akka" % "akka-http-spray-json-experimental_2.11" % akkaVersion,
    "com.typesafe.akka" %% "akka-slf4j" % akkaVersion,

    "org.mongodb" % "mongo-java-driver" % "3.4.1",
    "org.apache.kafka" %% "kafka" % "0.10.1.1",
    "org.apache.kafka" % "kafka-clients" % "0.10.1.1",

    //test
    "org.scalatest" %% "scalatest" % "2.2.5" % "test",
    "com.typesafe.akka" %% "akka-http-testkit" % "10.0.9" % "test",
    "de.flapdoodle.embed" % "de.flapdoodle.embed.mongo" % "2.0.0" % "test"
  )
}

parallelExecution in Test := false

2) And imports are,

import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._
import spray.json.DefaultJsonProtocol._

object GetMusicResources {

  val music_get_api =
    path("music") {
      get {
        complete {
          List("my data1")
        }
      }
    }
}

3) Tests

  Get("/music") ~> GetMusicResources.music_get_api ~> check {
    val response1: Future[ByteString] = response.entity.toStrict(300.millis).map {_.data }

    response1.map(_.utf8String).map { responseString =>
      responseString shouldBe """["my data1"]"""
    }

  }
Spyglass answered 6/7, 2017 at 0:50 Comment(0)
K
0

In my case, I was missing the second import in :

import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._
import spray.json.DefaultJsonProtocol._  // <= this one

In case anyone stumble into the same issue

Kiva answered 29/3, 2020 at 11:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.