environment: play2.3 with reactivemongo
I read the reactivemongo coast-to-coast article and liked the foundation of the article. Many of the examples are still beyond my comprehension at the moment, but I'm getting there.
As part of exploring this approach I am building a simple contacts REST api. The method passes a parent-id via the URL and the body contains the rest. There are 3 things I am stuck on.
- How do I add validation rules like min/max lengths to strings
- How do I make a string value optional
- How do I inject a parameter into the Json value
- How do I add a sub-section to the Json structure for address?
Is there a better way of implementing this?
This first section is the transform details, but I want to add max-length validation and change some fields to being optional.
val validateContact: Reads[JsObject] = (
(__ \ 'fullname).json.pickBranch and
(__ \ 'email).json.pickBranch( Reads.of[JsString] keepAnd Reads.email ) and
(__ \ 'phone).json.pickBranch and
(__ \ 'mobile).json.pickBranch( Reads.of[JsString] ) and
(__ \ 'labels).json.copyFrom(labelsOrEmptyArray)
//TODO: include address { street1, city, state, zip }
).reduce
val validateLabels = Reads.verifyingIf( (arr: JsArray) => !arr.value.isEmpty)(Reads.list[String])
val labelsOrEmptyArray = ((__ \ 'labels).json.pick[JsArray] orElse Reads.pure(Json.arr())) andThen validateLabels
val generateId = (__ \ '_id \ '$oid).json.put( JsString(BSONObjectID.generate.stringify) )
val generateCreated = (__ \ 'created \ '$date).json.put( JsNumber((new java.util.Date).getTime) )
val addMongoIdAndDate: Reads[JsObject] = __.json.update( (generateId and generateCreated).reduce )
This is the REST call on the controller. Notice the parentid parameter that needs to be added to the Json for storage in Mongo.
def create(parentid:BSONObjectID) = Action.async(parse.json) { implicit request =>
request.body.transform(validateContact andThen addMongoIdAndDate).map { result =>
collection.insert(result).map { LastError =>
Logger.debug(s"Successfully inserted with LastError: $LastError")
Created
}
}.getOrElse(Future.successful(BadRequest("Invalid json")))
}
Adding "keepAnd Reads.maxLength(20)" does not compile yet many examples show it in use? Is there a way to extend the validation feature set and add my own?
Update1: I am learning Scala so there is likely some simple things about the language I have overlooked or misunderstood at this point. I'm more familiar with Play1/Java from a while back.
Update2: I also noticed the "PickBranch" call does not distinguish between a string value or an object. How have others dealt with that?