Reputation: 89
I need to write decoder/encoder for akka.http.scaladsl.model.HttpHeader
abstract class HttpHeader extends jm.HttpHeader with ToStringRenderable {
def name: String
def value: String
def lowercaseName: String
def is(nameInLowerCase: String): Boolean = lowercaseName == nameInLowerCase
def isNot(nameInLowerCase: String): Boolean = lowercaseName != nameInLowerCase
}
i've tried to use derive encode and decode, but it didn't work
implicit val jsonDecoder: Decoder[HttpHeader] = deriveDecoder[HttpHeader]
implicit val jsonEncoder: Encoder[HttpHeader] = deriveEncoder[HttpHeader]
just getting an error could not find Lazy implicit value of type io.circe.generic.decoding.DerivedDecoder[akka.http.scaladsl.model.HttpHeader]
Upvotes: 0
Views: 1580
Reputation: 139058
Circe's generic derivation (deriveDecoder
, etc.) only works for types that it recognizes as "algebraic data types" (which in Scala means case classes and sealed hierarchies of case classes).
You can definitely use Circe with types like your HttpHeader
, but you'll have to be a little more explicit about how you want them encoded. Part of the reason for this is that there are many possible ways you could encode values of this type—e.g. do you want derived properties like the lowercaseName
value included in the serialisation?
Here's one possible way to write instances for this type:
import io.circe.{Decoder, Encoder}
abstract class HttpHeader {
def name: String
def value: String
def lowercaseName: String
def is(nameInLowerCase: String): Boolean = lowercaseName == nameInLowerCase
def isNot(nameInLowerCase: String): Boolean = lowercaseName != nameInLowerCase
}
implicit val decodeHttpHeader: Decoder[HttpHeader] =
Decoder.forProduct2("name", "value") {
(n: String, v: String) => new HttpHeader {
val name = n
val value = v
def lowercaseName = v.toLowerCase
}
}
implicit val encodeHttpHeader: Encoder[HttpHeader] =
Encoder.forProduct2("name", "value") { header =>
(header.name, header.value)
}
Which works like this:
scala> import io.circe.syntax._, io.circe.jawn.decode
import io.circe.syntax._
import io.circe.jawn.decode
scala> decode[HttpHeader]("""{ "name": "ABC", "value": "XYZ" }""")
res0: Either[io.circe.Error,HttpHeader] = Right($anon$1@dcd9c89b)
scala> res0.map(_.asJson)
res1: scala.util.Either[io.circe.Error,io.circe.Json] =
Right({
"name" : "ABC",
"value" : "XYZ"
})
You could also get lower-level, building up the instances using flatMap
or other combinators directly, but most of the time in situations like this forProductN
is what you want.
Upvotes: 8