From a3abbd502783df6df4de98c5dbf0c8eff81cb511 Mon Sep 17 00:00:00 2001 From: adamw Date: Wed, 18 Oct 2017 16:25:07 +0200 Subject: json4s support --- .../com/softwaremill/sttp/json4s/package.scala | 14 ++++ .../scala/com/softwaremill/sttp/Json4sTests.scala | 75 ++++++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 json/json4s/src/main/scala/com/softwaremill/sttp/json4s/package.scala create mode 100644 json/json4s/src/test/scala/com/softwaremill/sttp/Json4sTests.scala (limited to 'json/json4s') diff --git a/json/json4s/src/main/scala/com/softwaremill/sttp/json4s/package.scala b/json/json4s/src/main/scala/com/softwaremill/sttp/json4s/package.scala new file mode 100644 index 0000000..4c7aa36 --- /dev/null +++ b/json/json4s/src/main/scala/com/softwaremill/sttp/json4s/package.scala @@ -0,0 +1,14 @@ +package com.softwaremill.sttp + +import org.json4s._ +import org.json4s.native.Serialization.{read, write} + +package object json4s { + implicit def json4sBodySerializer[B <: AnyRef]( + implicit formats: Formats = DefaultFormats): BodySerializer[B] = + b => StringBody(write(b), Utf8, Some(ApplicationJsonContentType)) + + def asJson[B: Manifest]( + implicit formats: Formats = DefaultFormats): ResponseAs[B, Nothing] = + asString(Utf8).map(s => read[B](s)) +} diff --git a/json/json4s/src/test/scala/com/softwaremill/sttp/Json4sTests.scala b/json/json4s/src/test/scala/com/softwaremill/sttp/Json4sTests.scala new file mode 100644 index 0000000..bb4a774 --- /dev/null +++ b/json/json4s/src/test/scala/com/softwaremill/sttp/Json4sTests.scala @@ -0,0 +1,75 @@ +package com.softwaremill.sttp + +import org.json4s.ParserUtil.ParseException +import org.scalatest._ + +import scala.language.higherKinds + +class Json4sTests extends FlatSpec with Matchers with EitherValues { + import json4s._ + import Json4sTests._ + + "The json4s module" should "encode arbitrary json bodies" in { + val body = Outer(Inner(42, true, "horses"), "cats") + val expected = """{"foo":{"a":42,"b":true,"c":"horses"},"bar":"cats"}""" + + val req = sttp.body(body) + + extractBody(req) shouldBe expected + } + + it should "decode arbitrary bodies" in { + val body = """{"foo":{"a":42,"b":true,"c":"horses"},"bar":"cats"}""" + val expected = Outer(Inner(42, true, "horses"), "cats") + + val responseAs = asJson[Outer] + + runJsonResponseAs(responseAs)(body) shouldBe expected + } + + it should "fail to decode invalid json" in { + val body = """not valid json""" + + val responseAs = asJson[Outer] + + an[ParseException] should be thrownBy runJsonResponseAs(responseAs)(body) + } + + it should "set the content type" in { + val body = Outer(Inner(42, true, "horses"), "cats") + val req = sttp.body(body) + + val ct = req.headers.toMap.get("Content-Type") + + ct shouldBe Some(contentTypeWithEncoding(ApplicationJsonContentType, Utf8)) + } + + def extractBody[A[_], B, C](request: RequestT[A, B, C]): String = + request.body match { + case StringBody(body, "utf-8", Some(ApplicationJsonContentType)) => + body + case wrongBody => + fail( + s"Request body does not serialize to correct StringBody: $wrongBody") + } + + def runJsonResponseAs[A](responseAs: ResponseAs[A, Nothing]): String => A = + responseAs match { + case responseAs: MappedResponseAs[_, A, Nothing] => + responseAs.raw match { + case ResponseAsString("utf-8") => + responseAs.g + case ResponseAsString(encoding) => + fail( + s"MappedResponseAs wraps a ResponseAsString with wrong encoding: $encoding") + case _ => + fail("MappedResponseAs does not wrap a ResponseAsString") + } + case _ => fail("ResponseAs is not a MappedResponseAs") + } +} + +object Json4sTests { + case class Inner(a: Int, b: Boolean, c: String) + case class Outer(foo: Inner, bar: String) +} -- cgit v1.2.3