Lets say I have this case class:
case class Foo(bar: String, baz: Boolean = false)
which is used in when decoding/encoding API requests/responses using akka-http-json
in an example similar to this:
import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.server.Directives
import akka.stream.{ ActorMaterializer, Materializer }
import scala.io.StdIn
object ExampleApp {
private final case class Foo(bar: String, baz: Boolean = false)
def main(args: Array[String]): Unit = {
implicit val system = ActorSystem()
implicit val mat = ActorMaterializer()
Http().bindAndHandle(route, "127.0.0.1", 8000)
StdIn.readLine("Hit ENTER to exit")
system.terminate()
}
private def route(implicit mat: Materializer) = {
import Directives._
import FailFastCirceSupport._
import io.circe.generic.auto._
pathSingleSlash {
post {
entity(as[Foo]) { foo =>
complete {
foo
}
}
}
}
}
}
This works fine as long as the json message includes the baz
field. However, I want to be able to send a json message {bar: "something"}
and let the result use Foo
's default value for baz
. Is there any configuration in circe
or akka-http-json
that could make this work?
Also, would be nice to ignore the baz
field when encoding to json again, but this is not that important.
Edit:
I know I can do something like this:
implicit val fooEncoder: Encoder[Foo] = new Encoder[Foo] {
final def apply(a: Foo): Json = Json.obj(
("id", Json.fromString(a.bar))
)
}
implicit val fooDecoder: Decoder[Foo] = new Decoder[Decoder] {
final def apply(c: HCursor): Decoder.Result[Decoder] =
for {
bar <- c.downField("bar").as[String]
} yield {
Foo(bar)
}
}
but was hoping for an easier-to-maintain solution, solving the general case of not requiring the default fields in the json message.
You can do this using the circe-generic-extras package. It's a separate dependency you have to put in your build. For sbt, that's:
libraryDependencies += "io.circe" %% "circe-generic-extras" % "0.8.0"
Then, in your route function, replace
import io.circe.generic.extras.Configuration
import io.circe.generic.auto._
with:
import io.circe.generic.extras.auto._
implicit val customConfig: Configuration = Configuration.default.withDefaults
The encoders this generates will always include the default fields.
For more info see the circe release notes at: https://github.com/circe/circe/releases/tag/v0.6.0-RC1
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With