问题描述
使用 Scala 实现 Rest API 服务我使用的是 Akka Http v10.2.3 和 Circe v0.13.0。
假设我有这个端点:
import io.circe.generic.auto._
...
pathPrefix("test") {
post {
entity(as[SomeData]) { data =>
// do something with the data (instance of SomeData)
...
complete(StatusCodes.OK)
}
}
}
和 SomeData 案例类:
case class SomeData(someString: String,someInt: Int = 0)
如果我用这个 json 到达这个端点:
{ "someString": "value","someInt": 123}
然后 Circe 会将 SomeData(value,123)
存储在变量 data
中。
如果我用这个 json 到达端点:
{ "someString": "value"}
然后 Circe 将失败,因为缺少 someInt
。
当有效负载为 {"someString: "value"}
且 json 中缺少 someInt
时(不使用 Option),Circe 是否可以将值 0 设置为案例类中的默认值?
更新:
我正在尝试使用 io.circe.generic.extras
但我无法让它工作(此时我在两个源中创建了一个隐式 val 但它也不起作用)这里是完整的源:
package com.defaultValues
import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.server.Directives._
import de.heikoseeberger.akkahttpcirce.FailFastCirceSupport
import scala.util.Success
import scala.util.Failure
import SomeData._
object SomeApi extends App with FailFastCirceSupport {
val serviceName: String = "default-values"
implicit val system: ActorSystem = ActorSystem(serviceName)
import system.dispatcher
import io.circe.generic.extras.Configuration
import io.circe.generic.extras.auto._
implicit val someDataConfig: Configuration = Configuration.default.withDefaults
val routes = pathPrefix("default-values") {
post {
entity(as[SomeData]) { data =>
println(s"POST /test,body $data")
complete(data)
}
}
}
Http()
.newServerAt("localhost",8084)
.bind(routes)
.onComplete {
case Success(_) => println(s"app started $serviceName")
case Failure(exception) => println(s"app failed to start $serviceName",exception)
}
}
package com.defaultValues
import io.circe.{Decoder,Encoder}
import io.circe.generic.semiauto.{deriveDecoder,deriveEncoder}
case class SomeData(someString: String,someInt: Int = 0)
object SomeData {
import io.circe.generic.extras.Configuration
implicit val customConfig: Configuration = Configuration.default.withDefaults
implicit val someDataDecoder: Decoder[SomeData] = deriveDecoder[SomeData]
implicit val someDataEncoder: Encoder[SomeData] = deriveEncoder[SomeData]
}
build.sbt:
scalaVersion := "2.13.2"
val akkaVersion = "2.6.9"
val akkaHttpVersion = "10.2.0"
val akkaHttpCirceVersion = "1.31.0"
val circeVersion = "0.13.0"
libraryDependencies ++= Seq(
"com.typesafe.akka" %% "akka-actor-typed" % akkaVersion,"com.typesafe.akka" %% "akka-cluster-typed" % akkaVersion,"com.typesafe.akka" %% "akka-http" % akkaHttpVersion,"de.heikoseeberger" %% "akka-http-circe" % akkaHttpCirceVersion,"io.circe" %% "circe-core" % circeVersion,"io.circe" %% "circe-generic" % circeVersion,"io.circe" %% "circe-parser" % circeVersion,"io.circe" %% "circe-refined" % circeVersion,"io.circe" %% "circe-generic-extras" % circeVersion,)
示例: 当我发送此有效负载时:
{ "someString": "value1" }
我明白了:
The request content was malformed:
Attempt to decode value on failed cursor: DownField(someInt)
解决方法
我找到了解决方案:
取而代之的是:
application_name.py
我不得不使用这个:
implicit val someDataDecoder: Decoder[SomeData] = deriveDecoder[SomeData]
implicit val someDataEncoder: Encoder[SomeData] = deriveEncoder[SomeData]
并添加此导入:
implicit val someDataDecoder: Decoder[SomeData] = deriveConfiguredDecoder
implicit val someDataEncoder: Encoder[SomeData] = deriveConfiguredEncoder