Last active
June 28, 2017 17:19
-
-
Save mikemckibben/fad4328de85a79a06bf3 to your computer and use it in GitHub Desktop.
Example Unmarshalling an Either[A, B] with spray-json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import org.specs2.mutable.Specification | |
import spray.http.{HttpResponse, StatusCodes} | |
import spray.httpx.SprayJsonSupport | |
import spray.httpx.marshalling._ | |
import spray.httpx.unmarshalling._ | |
import spray.json._ | |
/*** | |
* scalaVersion := "2.11.2" | |
* | |
* resolvers += "spray repo" at "http://repo.spray.io" | |
* | |
* libraryDependencies ++= Seq( | |
* "com.typesafe.akka" %% "akka-actor" % "2.3.5", | |
* "com.typesafe.akka" %% "akka-slf4j" % "2.3.5", | |
* "com.typesafe.akka" %% "akka-testkit" % "2.3.5" % "test", | |
* "org.apache.logging.log4j" % "log4j-api" % "2.0.2", | |
* "org.apache.logging.log4j" % "log4j-slf4j-impl" % "2.0.2", | |
* "org.apache.logging.log4j" % "log4j-jcl" % "2.0.2", | |
* "org.slf4j" % "slf4j-api" % "1.7.7", | |
* "io.spray" %% "spray-can" % "1.3.1", | |
* "io.spray" %% "spray-routing" % "1.3.1", | |
* "io.spray" %% "spray-json" % "1.2.6", | |
* "io.spray" %% "spray-testkit" % "1.3.1" % "test", | |
* "org.specs2" %% "specs2" % "2.4.1" % "test" | |
* ) | |
*/ | |
class EitherExampleSpec extends Specification with SprayJsonSupport with DefaultJsonProtocol { | |
object Data { | |
case class Success[A](result: A) | |
object Success { | |
implicit def successFormat[A](implicit format: JsonFormat[A]) = new RootJsonFormat[Success[A]] { | |
override def write(value: Success[A]): JsValue = { | |
JsObject("ok" -> JsBoolean(true), "result" -> format.write(value.result)) | |
} | |
override def read(json: JsValue): Success[A] = { | |
val root = json.asJsObject | |
(root.fields.get("ok"), root.fields.get("result")) match { | |
case (Some(JsTrue), Some(jsValue)) => Success(format.read(jsValue)) | |
case _ => deserializationError("JSON not a Success") | |
} | |
} | |
} | |
} | |
case class Failure(reason: String) | |
object Failure { | |
implicit object failureFormat extends RootJsonFormat[Failure] { | |
override def write(value: Failure): JsValue = { | |
JsObject("ok" -> JsBoolean(false), "error" -> JsString(value.reason)) | |
} | |
override def read(json: JsValue): Failure = { | |
val root = json.asJsObject | |
(root.fields.get("ok"), root.fields.get("error")) match { | |
case (Some(JsFalse), Some(JsString(reason))) => Failure(reason) | |
case _ => deserializationError("JSON not a Failure") | |
} | |
} | |
} | |
} | |
type Result[A] = Either[Failure, Success[A]] | |
implicit def rootEitherFormat[A : RootJsonFormat, B : RootJsonFormat] = new RootJsonFormat[Either[A, B]] { | |
val format = DefaultJsonProtocol.eitherFormat[A, B] | |
def write(either: Either[A, B]) = format.write(either) | |
def read(value: JsValue) = format.read(value) | |
} | |
} | |
"Example Unmarshalling JSON Response as Either[Failure, Success]" >> { | |
import Data._ | |
"unmarshalling a Success[String] json response" in { | |
val result: Result[String] = Right(Success("Success!")) | |
val jsonResponse = HttpResponse(status = StatusCodes.OK, entity = marshalUnsafe(result)) | |
jsonResponse.as[Result[String]] must beRight(Right(Success("Success!"))) | |
} | |
"unmarshalling a Failure json response" in { | |
val result: Result[String] = Left(Failure("Failure!")) | |
val jsonResponse = HttpResponse(status = StatusCodes.OK, entity = marshalUnsafe(result)) | |
jsonResponse.as[Result[String]] must beRight(Left(Failure("Failure!"))) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment