2015-07-30 2 views
1

Я работаю над REST-API, реализованным в Скалатре, и с использованием reactivemongo. Моя постоянная модель реализована с использованием классов case, а тонкий слой репозитория использует общий подход для bson < -> сопоставление классов через DocumentReader/DocumentWriter (через неявные преобразователи в случае класса сопутствующего объекта).Scala + Reactivemongo: Управление пользовательскими читателями/писателями для REST-API

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 к случаю классов второй обращенных JSON (формат вывода из REST-API).

Все это прекрасно, и я вполне доволен тем, насколько хорошо все интегрируется.

Во многих случаях мне не нужно работать с объектами домена (экземплярами класса case) и просто хотите передать данные, поступающие из базы данных, в ответ на http. Все промежуточные преобразования в этих сценариях являются накладными. Я также хочу контролировать, какие поля подвергаются (я когда-то использовал Йогу и Джексон в проекте Java).

Возможные решения для этого было бы:

  • имеют общий репозиторий, который просто преобразует в структуре карты в качестве промежуточного формата.
  • Управление неявными конвертерами, доступными для драйвера по каждому запросу, и классы записей для разных «представлений»
  • Использовать BSONDocument как промежуточный формат и сделать слой REST понятным BSON посредством преобразования строки bson =>.

Интересно, что такое лучший подход, и если у кого-то есть опыт работы с этим конкретным сценарием. Может быть, я даже упустил еще один хороший вариант? Обратная связь очень приветствуется.

+0

Вы можете сделать побережье до побережья с помощью 'JsValue' или' JsObject'. – cchantep

+0

play-reactivemongo делает что-то подобное, и я думаю, что вы могли бы повторно использовать эту идею. – Barry

+0

Побережье к побережью (https://www.playframework.com/documentation/2.1.0/ScalaJsonTransformers) выглядит очень многообещающим. Мне просто интересно, как уменьшить собственный код, необходимый для этого. Возможно, можно было бы реализовать более удобную для пользователя DSL с сопоставлением с образцом, которая переводится на комбинации трансформаторов. Но это будущее :) @cchantep Возможно, вы могли бы сделать свой комментарий ответом - я мог бы принять его :) – bennidi

ответ

0

Чтобы контролировать, какие поля выставлены, вам, вероятно, придется писать читателей и писателей. Ниже приведен пример, извлеченный из этого проекта 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)) 
} 
+0

Использование макросов Play JSON было бы проще в этих случаях. – cchantep