Need a simple example on how to consume a HTTP Service with Json unmarshalling

495 views
Skip to first unread message

Mo Batista

unread,
Mar 30, 2017, 8:28:38 AM3/30/17
to Akka User List
I'm new to Akka-Http please bear with me.

What I'm trying to do is

1. Connect to a Restful service
2. Unmarshall the json payload into the following case class structure


case class ColorBlob(url: String, averageColor: String, classificationColor: String)
case class ColorBlobsResponse(colorBlobs: Map[String, Option[ColorBlob]])

In theory this should be simple, but it turns out that anything on this topic is either outdated or way over my head, as in this article
http://malaw.ski/2016/04/10/hakk-the-planet-implementing-akka-http-marshallers/.

http://doc.akka.io/docs/akka-http/10.0.1/scala/http/common/unmarshalling.html doesn't explain how to actually write an unmarshaller

This is where I got so far:

Issuing the request

val request = HttpRequest(method = HttpMethods.GET, uri = s"https://colorblobs.service.net/ws/colorblobs/en?productCodes=904655")
val future = Http().singleRequest(request)
val result: ColorBlobsResponse = Await.result(future.flatMap(Unmarshal(_).to[ColorBlobsResponse]), Duration.Inf)


Providing the  unmarshaller. This is also where I got stuck

object ColorBlobJsonProtocol extends DefaultJsonProtocol {
implicit val colorBlobsUnmarshaller = new FromResponseUnmarshaller[ColorBlobsResponse] {
implicit val colorBlobsFormat = jsonFormat1(ColorBlobsResponse)
def apply(response: HttpResponse) = try {
val entity: ResponseEntity = response.entity
??????

}
}
}


Now that I have ResponseEntity what would be the next step?

Maybe there is a blog article explaining what  jsonFormat1, DefaultJsonProtocol and FromResponseUnmarshaller actually do?

 I'm using akka-http 10.0.5 btw.


Thanks a lot!



Konrad Malawski

unread,
Mar 30, 2017, 8:37:52 AM3/30/17
to akka...@googlegroups.com, Mo Batista

On 30 March 2017 at 14:28:34, Mo Batista (mouni...@gmail.com) wrote:

I'm new to Akka-Http please bear with me.

Hello Mo and welcome to Akka :-


What I'm trying to do is

1. Connect to a Restful service
2. Unmarshall the json payload into the following case class structure

It's as simple as these docs really: http://doc.akka.io/docs/akka-http/10.0.5/scala/http/common/unmarshalling.html#using-unmarshallers

So you just need: 

    implicit val colorBlobsFormat = jsonFormat1(ColorBlobsResponse) // this already provided all the needed marshallers
    // implicit materializer in Scope AFAIR too
    import system.dispatcher
Unmarshal(entity).to[ColorBlob]

In theory this should be simple, but it turns out that anything on this topic is either outdated or way over my head, as in this article
http://malaw.ski/2016/04/10/hakk-the-planet-implementing-akka-http-marshallers/

That's about writing custom unmarshallers which is rather advanced - you don't need to do that.


http://doc.akka.io/docs/akka-http/10.0.1/scala/http/common/unmarshalling.html doesn't explain how to actually write an unmarshaller




This is where I got so far:

Issuing the request

val request = HttpRequest(method = HttpMethods.GET, uri = s"https://colorblobs.service.net/ws/colorblobs/en?productCodes=904655")
val future = Http().singleRequest(request)
val result: ColorBlobsResponse = Await.result(future.flatMap(Unmarshal(_).to[ColorBlobsResponse]), Duration.Inf)



Small note here, I would strongly recommend never using Duration.Inf, even in sample code as you might get used to it and in general it simply is a very bad idea to block infinitely.
Put `import scala.concurrent.duration._` and `2.seconds` instead for example.

Providing the  unmarshaller. This is also where I got stuck

You don't need to do any of the manual Unmarshaller building, it's all ready once you did the jsonFormat call :)


Now that I have ResponseEntity what would be the next step?

No need to go so "manual" :-) Check the docs above.


Maybe there is a blog article explaining what  jsonFormat1, DefaultJsonProtocol and FromResponseUnmarshaller actually do?




 I'm using akka-http 10.0.5 btw.

Thanks for providing that info, people often forget to and it helps a lot to know that you're on the latest :)


Hope this helps,


-- 
Konrad `ktoso` Malawski
Akka @ Lightbend

Mo Batista

unread,
Mar 30, 2017, 10:57:51 AM3/30/17
to Akka User List, mouni...@gmail.com

package xxx

import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport
import akka.http.scaladsl.model._
import akka.http.scaladsl.unmarshalling.Unmarshal
import akka.stream.{ActorMaterializer, Materializer}
import org.scalatest.concurrent.ScalaFutures
import org.scalatest.{BeforeAndAfter, FlatSpec, MustMatchers}
import org.scalatest.mock.MockitoSugar
import spray.json.DefaultJsonProtocol
import scala.concurrent.{Await, ExecutionContextExecutor, Future}
import akka.http.scaladsl.server.Directives


case class ColorBlob(url: String, averageColor: String, classificationColor: String)
case class ColorBlobsResponse(colorBlobs: Map[String, Option[ColorBlob]])

trait JsonSupport extends SprayJsonSupport with DefaultJsonProtocol {
implicit val format1 = jsonFormat3(ColorBlob)
implicit val format2 = jsonFormat1(ColorBlobsResponse) // this already provided all the needed marshallers
}

class ColorBlobRestTest
extends FlatSpec
with MockitoSugar
with BeforeAndAfter
with MustMatchers
with ScalaFutures
with JsonSupport
with Directives {

implicit val system: ActorSystem = ActorSystem()
implicit val executor: ExecutionContextExecutor = system.dispatcher
implicit val materializer: Materializer = ActorMaterializer()

"this" should "work" in {
val request = HttpRequest(method = HttpMethods.GET, uri = s"https://colorblobs.svc.dglecom.net/ws/colorblobs/de?productCodes=904655")
val futureResponse: Future[HttpResponse] = Http().singleRequest(request)

val futureColorBlobResponse: Future[ColorBlobsResponse] = futureResponse.flatMap { response: HttpResponse =>

val entity: ResponseEntity = response.entity
      Unmarshal(entity).to[ColorBlobsResponse]
}

import scala.concurrent.duration._
val colorBlobsResponse: ColorBlobsResponse = Await.result(futureColorBlobResponse, 1000.millis)

assert(1==1)

}
}




Hi Konrad

yes it does !

Here is my working example. I dumbed it down for future reference, if anyone is interested. The solution is indeed much easier than I thought! Thanks again for your help! Yeah, I know the documentation is there, but everything is a little bit hard to follow.

have a good one! :)

Konrad Malawski

unread,
Mar 30, 2017, 11:00:09 AM3/30/17
to akka...@googlegroups.com, Mo Batista
Glad you worked it out :)
We're working on improving the docs a lot in the very near future, hope that'll help newcomers.

Happy hakking!

-- 
Konrad `ktoso` Malawski
Akka @ Lightbend

--
>>>>>>>>>> Read the docs: http://akka.io/docs/
>>>>>>>>>> Check the FAQ: http://doc.akka.io/docs/akka/current/additional/faq.html
>>>>>>>>>> Search the archives: https://groups.google.com/group/akka-user
---
You received this message because you are subscribed to the Google Groups "Akka User List" group.
To unsubscribe from this group and stop receiving emails from it, send an email to akka-user+...@googlegroups.com.
To post to this group, send email to akka...@googlegroups.com.
Visit this group at https://groups.google.com/group/akka-user.
For more options, visit https://groups.google.com/d/optout.
Reply all
Reply to author
Forward
0 new messages