我正在开发一个用scala实现的REST-API,并使用reactivemongo。我的持久模型是使用case类实现的,瘦存储库层使用通过DocumentReader/DocumentWriter(通过case类伴侣对象中的隐式转换器)进行bson<->类映射的通用方法。
case class Address(street: String, number: String, city: String, zip: String)
object Address{
implicit val addressHandler = Macros.handler[Address]
implicit val addressFmt = Json.format[Address]
}
第一个格式化器将bson映射为case类,第二个格式化器将转换为json (REST-API的输出格式)。
这一切都很好,我很高兴所有的东西都很好地集成在一起。
在许多情况下,我不需要操作域对象(case类实例),只是想将来自数据库的数据写入http响应。在这些场景中,所有中间转换都是开销。我还想控制哪些字段是公开的(我曾经在Java项目中使用Yoga和Jackson)。
可能的解决方案是:
- 有一个通用的存储库,它可以简单地转换为Map结构作为中间格式。
- 控制驱动程序在每个查询基础上可用的隐式转换器,并为不同的"视图"编写case类
- 使用BSONDocument作为中间格式,通过BSON =>字符串转换使REST层理解BSON。
我想知道最好的方法是什么,如果有人有这种特殊情况的经验。也许我甚至错过了另一个好的选择?
要控制公开哪些字段,可能需要编写一个Readers和Writers。下面是从这个项目中提取的一个例子https://github.com/luongbalinh/play-mongo。
import java.time.ZonedDateTime
case class User(override val id: Option[Long] = None,
firstName: String,
lastName: String,
age: Int,
active: Boolean,
createdDate: Option[ZonedDateTime] = None,
updatedDate: Option[ZonedDateTime] = None
) extends IdModel[User] {
override def withNewId(id: Long): User = this.copy(id = Some(id))
}
object User {
import play.api.libs.functional.syntax._
import play.api.libs.json._
implicit val userReads: Reads[User] = (
(JsPath "id").readNullable[Long] and
(JsPath "firstName").read[String] and
(JsPath "lastName").read[String] and
(JsPath "age").read[Int] and
(JsPath "active").read[Boolean] and
(JsPath "createdDate").readNullable[ZonedDateTime] and
(JsPath "updatedDate").readNullable[ZonedDateTime]
)(User.apply _)
implicit val userWrites: Writes[User] = (
(JsPath "id").writeNullable[Long] and
(JsPath "firstName").write[String] and
(JsPath "lastName").write[String] and
(JsPath "age").write[Int] and
(JsPath "active").write[Boolean] and
(JsPath "createdDate").writeNullable[ZonedDateTime] and
(JsPath "updatedDate").writeNullable[ZonedDateTime]
)(unlift(User.unapply))
}