Reputation: 45
How is the createUser or updateUser using the unmarshalValueJs function and passing arguments.
package controllers.user
import play.api._
import play.api.mvc._
import play.api.libs.json._
import play.api.libs.json.Reads._
import play.api.libs.functional.syntax._
import services.user.UserServiceComponent
import domain.user.User
trait UserController extends Controller {
self: UserServiceComponent =>0
def emailAlreadyExists(implicit reads: Reads[String]) =
Reads[String](js => reads.reads(js).flatMap { e =>
userService.tryFindByEmail(e).map(_ => JsError("error.custom.emailAlreadyExists")).getOrElse(JsSuccess(e))
})
implicit val userReads = (__ \ "email").read[String](email andKeep emailAlreadyExists)
.map(resource => UserResource(resource))
implicit val userWrites = new Writes[User] {
override def writes(user: User): JsValue = {
Json.obj(
"id" -> user.id,
"email" -> user.email
)
}
}
What create User passes to the unmarshalJsValue? Where does resource come from?
def createUser = Action(parse.json) {request =>
unmarshalJsValue(request) { resource: UserResource =>
val user = User(Option.empty, resource.email)
userService.createUser(user)
Created
}
}
def updateUser(id: Long) = Action(parse.json) {request =>
unmarshalJsValue(request) { resource: UserResource =>
val user = User(Option(id), resource.email)
userService.updateUser(user)
NoContent
}
}
def findUserById(id: Long) = Action {
val user = userService.tryFindById(id)
if (user.isDefined) {
Ok(Json.toJson(user))
} else {
NotFound
}
}
def deleteUser(id: Long) = Action {
userService.delete(id)
NoContent
}
What is R over here? What get passed back to the createUser?
def unmarshalJsValue[R](request: Request[JsValue])(block: R => Result)(implicit rds : Reads[R]): Result =
request.body.validate[R](rds).fold(
valid = block,
invalid = e => {
val error = e.mkString
Logger.error(error)
BadRequest(error)
}
)
}
case class UserResource(email: String)
Upvotes: 0
Views: 73
Reputation: 36491
R
is a type variable. The definition def unmarshalJsValue[R](request: Request[JsValue])(block: R => Result)(implicit rds : Reads[R])
reads:
I'm a method called unmarshallJsValue
.
I require a type parameter that could potentially be anything.
I require a value of Request[JsValue]
(presumably a request contianin a JSON entity).
I require a function that, given some value of type R
, produces a Result
.
I require a value to be in implicit
scope that is a Reads
for type R
. In other words, I need a way to convert a JsValue
to an R
, whatever R
might happen to be. (If you look at the docs for Reads
, you'll notice that its only method, reads
, has this effect.)
To put it all together, entire function just says, give me some block of code that produces a Result
from some piece of data I know how to convert to from JSON. The body of the function simply attempts to convert the JSON to the desired type (known as unmarshalling). If this succeeds, it runs the block. Otherwise, you get a BadRequest
client error.
The compiler can't know whether the JSON that gets provided in real life by the client will be convertible to some type R
, but it can require a JSON -> R
converter, and some error handling code if it fails on real data.
Upvotes: 1