0
votes

I consume some data from a singleRequest with a custom body, and i tried to serialize it to a custom case class with Unmarshall but it doesn't work; the body response is like:

{
    "teams": [
        {
            "id": "21312",
            "name": "team1",
            "color": "#4169E1",
            "avatar": null,
            "members": [
                {
                    "user": {
                        "id": 12737636,
                        "username": "user2",
                        "email": "[email protected]",
                        "color": "#827718",
                        "profilePicture": null,
                        "initials": "U2",
                        "role": 4,
                        "custom_role": null,
                        "last_active": "1613419183004",
                        "date_joined": "1612542647748",
                        "date_invited": "1612542548880"
                    },
                    "invited_by": {
                        "id": 68732,
                        "username": "user1",
                        "color": "#f8306d",
                        "email": "[email protected]",
                        "initials": "U1",
                        "profilePicture": "https://attachments.clickup.com/profilePictures/image.jpg"
                    },
                    "can_see_time_spent": true,
                    "can_see_time_estimated": true,
                    "can_see_points_estimated": true,
                    "can_edit_tags": false
                },
                {
                    "user": {
                        "id": 12715129,
                        "username": "user3",
                        "email": "[email protected]",
                        "color": "#04a9f4",
                        "profilePicture": null,
                        "initials": "IM",
                        "role": 4,
                        "custom_role": null,
                        "last_active": "1613483780281",
                        "date_joined": "1611598611255",
                        "date_invited": "1611597360856"
                    },
                    "invited_by": {
                        "id": 4371505,
                        "username": "user34",
                        "color": "#f8306d",
                        "email": "[email protected]",
                        "initials": "U34",
                        "profilePicture": "https://attachments.clickup.com/profilePictures/image.jpg"
                    },
                    "can_see_time_spent": true,
                    "can_see_time_estimated": true,
                    "can_see_points_estimated": true,
                    "can_edit_tags": false
                }
            ]
        }
    ]
}

Code to fetch the data:

val responseFuture = Http()
      .singleRequest(HttpRequest( method = GET ,uri = "https://apiRest/api/v2/team" )
        .withHeaders(RawHeader("authorization","xxxxxxxxxxxx")))

I have this case class to serialize it:

    case class Invited_By (id: Long, username:Option[String] , color : Option[String], email: Option[String], initials : Option[String], profilePicture: Option[String])
  case class User ( id: Long , username: Option[String] , email: Option[String] , color: Option[String] , profilePicture: Option[String] , initials: Option[String] , role: Option[Int], custom_role: Option[String] , last_active: Option[String] , date_joined: Option[String] , date_invited: Option[String] )
  case class Member (user: User, invited_By: Invited_By, can_see_time_spent: Boolean, can_see_time_estimated:Boolean, can_see_points_estimated:Boolean, can_edit_tags:Boolean)
  case class Team (id : String, name: Option[String], color: Option[String], avatar: Option[String], members: Seq[Member] )
  case class Teams( teams: Seq[Team] )

i tried with this; this didn't work :

import play.api.libs.json._
import play.api.libs.functional.syntax._

implicit val TeamsReads: Reads[Teams] = Json.reads[Teams]

    val responseFuture = Http()
      .singleRequest(HttpRequest( method = GET ,uri = "https://apiRest/api/v2/team" )
        .withHeaders(RawHeader("authorization","XXXXXXXXXXXX")))
      .flatMap{
        res =>
          Unmarshal(res).to[String]
            .map {
              data =>
                val jsValue:JsValue = Json.parse(data)
                val result: JsResult[Teams] = jsValue.validate[Teams]
                result
            }
        }

is there a better way to do it ??

note: i found akka-http-spray-json , but i don't know how to implement it

1

1 Answers

1
votes

In order to use akka-http-spray-json you need to import these libraries.

"com.typesafe.akka" %% "akka-http" % akkaHttpVersion,
  "com.typesafe.akka" %% "akka-http-spray-json" % akkaHttpVersion,
  "com.typesafe.akka" %% "akka-http-testkit" % akkaHttpVersion,
  "com.typesafe.akka" %% "akka-http2-support" % akkaHttpVersion,

Then follow the bellow steps to be able to Marshal and unmarshal JSON strings.

  • step 1 - import spray json import spray.json._
  • step 2 - create the JSON protocol. A trait that extends DefaultJsonProtocol. Note that the Chat class has 4 parameters, so I used jsonFormat4 in the protocol.
  • step 3 - extend the trait that you created
  • step 4 - add sprayJsonSupport

I have this small example which I consult everytime I need to add json support to akka:

import akka.actor.{Actor, ActorLogging, ActorSystem, Props}
import akka.http.scaladsl.Http
import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport
import akka.http.scaladsl.server.Directives._
import akka.pattern.ask
import akka.util.Timeout
import spray.json._ // step 1 - import spray json
import scala.concurrent.Future
import scala.concurrent.duration._

// case class Player(nickname: String, characterClass: String, level: Int)
case class Chat(sender: String, receiver: String, message: String, groupChatName: String)

case object GetAllUsersInChat

case class AddUsers(player: Chat)

// step 2 - the JSON protocol
trait ChatJsonProtocol extends DefaultJsonProtocol {
  implicit val chatFormat = jsonFormat4(Chat)
}

class ChatActor extends Actor with ActorLogging {
  var users = Map[String, Chat]()

  override def receive: Receive = {
    case GetAllUsersInChat =>
      log.info(s"getting all users")
      sender() ! users.values.toList
    case AddUsers(user) =>
      log.info(s"trying to add user $user")
      users = users + (user.sender -> user)
    case _ => log.info(s"unknown message")
  }
}

// step 3 - extend ChatJsonProtocol
// step 4 - add sprayJsonSupport
object ChatMarshallingJSON extends ChatJsonProtocol with SprayJsonSupport {
  implicit val system = ActorSystem("ChatMarshallingJSON")
  val chatActor = system.actorOf(Props[ChatActor], "chatActor")
  // boot strap some users
  val chatusers = List(
    Chat("sender1", "receiver1", "message1", "groupChat1"),
    Chat("sender2", "receiver2", "message2", "groupChat2"),
    Chat("sender3", "receiver3", "message3", "groupChat3")
  )
  chatusers.foreach { user =>
    chatActor ! AddUsers(user)
  }

  implicit val defaultTimeout = Timeout(2 seconds)

  val chatRoutes = {
    path("api" / "chat") {
      get {
        // 3: get all users in the chat
        val allUsersInChatFuture: Future[List[Chat]] = (chatActor ? GetAllUsersInChat).mapTo[List[Chat]]
        complete(allUsersInChatFuture)
      }
    }
  }

  def main(args: Array[String]): Unit = {
    println("http GET localhost:8080/api/chat")
    Http()
      .newServerAt("localhost", 8080)
      .bindFlow(chatRoutes)
  }
}