2015-08-31 10 views
20

Così ho una funzione con la firma (akka.http.model.HttpResponse):Akka HttpResponse corpo leggere as String Scala

def apply(query: Seq[(String, String)], accept: String): HttpResponse 

ho semplicemente ottenere un valore in un test come:

val resp = TagAPI(Seq.empty[(String, String)], api.acceptHeader) 

voglio controllare il suo corpo in un qualcosa di test come:

resp.entity.asString == "tags" 

mia domanda è come posso ottenere il corpo della risposta come stringa?

+0

Rilevante: http://stackoverflow.com/q/31532838/390708 – Brian

+2

Si sta utilizzando 'Akka-http-testkit'? Se sì, puoi usare 'entityAs [String]' nel test per ottenere il corpo come valore di stringa. – jrudolph

+0

Ho bisogno di usare PlaySpec quindi non posso usare akka-http-testkit :( – tg44

risposta

16

Poiché Akka Http è basato su flussi, anche l'entità è in streaming. Se si ha realmente bisogno l'intera stringa in una sola volta, è possibile convertire la richiesta in ingresso in un Strict uno:

Questo viene fatto utilizzando il toStrict(timeout: FiniteDuration)(mat: Materializer) API per raccogliere la richiesta in un rigoroso entità all'interno di un limite dato tempo (questo è importante dal momento che non si vuole "cercare di raccogliere l'entità sempre" nel caso in cui la richiesta in ingresso realtà non finire mai):

import akka.stream.ActorFlowMaterializer 
import akka.actor.ActorSystem 

implicit val system = ActorSystem("Sys") // your actor system, only 1 per app 
implicit val materializer = ActorFlowMaterializer() // you must provide a materializer 

import system.dispatcher 
import scala.concurrent.duration._ 
val timeout = 300.millis 

val bs: Future[ByteString] = entity.toStrict(timeout).map { _.data } 
val s: Future[String] = bs.map(_.utf8String) // if you indeed need a `String` 
+0

Sembra essere un buon modo, ma che tipo di FlowMaterializer implicito stai usando? (Hai capito dall'importazione o usi qualche implementazione predefinita?) – tg44

+0

Puoi semplicemente crearne uno ad hoc o riutilizzare un'istanza esistente, ho modificato la mia risposta –

15
import akka.http.scaladsl.unmarshalling.Unmarshal 


    implicit val system = ActorSystem("System") 
    implicit val materializer = ActorFlowMaterializer() 

    val responseAsString: Future[String] = Unmarshal(entity).to[String] 
+0

Quale versione di akka-http-core usi per questo? Con 2.4.6, non trovo il 'akka.http. scaladsl.unmarshalling', ovunque. – akauppi

+1

@akauppi questo è 'akka-http-experimental' non' akka-http-core' – wlk

1

Purtroppo nel mio caso, Unmarshal a String non funzionava correttamente lamentarsi a: Unsupported Content-Type, supported: application/json. Sarebbe una soluzione più elegante, ma ho dovuto usare un altro modo. Nella mia prova ho usato Future estratto dalla entità della risposta e di attendere (da scala.concurrent) per ottenere il risultato dal futuro:

Put("/post/item", requestEntity) ~> route ~> check { 
     val responseContent: Future[Option[String]] = 
     response.entity.dataBytes.map(_.utf8String).runWith(Sink.lastOption) 

     val content: Option[String] = Await.result(responseContent, 10.seconds) 
     content.get should be(errorMessage) 
     response.status should be(StatusCodes.InternalServerError) 
    } 

Se avete bisogno di passare attraverso tutte le linee di una risposta, è possibile utilizzare runForeach di fonte:

response.entity.dataBytes.map(_.utf8String).runForeach(data => println(data)) 
1

Si può anche provare anche questo.

responseObject.entity.dataBytes.runFold(ByteString(""))(_ ++ _).map(_.utf8String) map println