eliot
eliot

Reputation: 1329

Scala Object From JSON Request

I have a controller method in my Scala Play project that takes JSON as input. I would like to turn this JSON into a model object I have.

Here is my controller method:

def broadcastPost = Action(parse.json) { request =>
  (request.body).asOpt[Post].map { post =>
    Post.create(post.channelId, post.message, post.datePosted, post.author)
    Ok(play.api.libs.json.Json.toJson(
      Map("status" -> "OK", "message" -> ("Post created"))
    ))
  }.getOrElse {
    BadRequest(play.api.libs.json.Json.toJson(
      Map("status" -> "Error", "message" -> ("Missing parameter [Post]"))
    ))
  }
}

And here is the model:

case class Post(id: Pk[Long], channelId: Long, message: String, datePosted: Date, author: String)

and its implicit formatter:

implicit val postFormat = (
  (__ \ "id").formatNullable[Long] and
  (__ \ "channelId").format[Long] and
  (__ \ "message").format[String] and
  (__ \ "datePosted").format[Date] and
  (__ \ "author").format[String]
  )((id, channelId, message, datePosted, author) => Post(id.map(Id(_)).getOrElse(NotAssigned), channelId, message, datePosted, author),
  (p: Post) => (p.id.toOption, p.channelId, p.message, p.datePosted, p.author))

When I send a POST request to that method with the following data:

{"channelId":1, "message":"Wanna get a game in?", "dateCreated":"5-15-2013", "author":"Eliot Fowler"}

I get the following response:

{"status":"Error","message":"Missing parameter [Post]"}

I am very new to Scala, so I may be overlooking something very simple here.

Upvotes: 3

Views: 1639

Answers (1)

James Roper
James Roper

Reputation: 12850

Instead of using asOpt, which loses the error, you should use validate, which will allow you to return the error message, and then see what the problem is, eg:

def broadcastPost = Action(parse.json) { request =>
  request.body.validate[Post].fold({ errors => 
    BadRequest(Json.obj(
      "status" -> "Error", 
      "message" -> "Bad JSON",
      "details" -> JsError.toFlatJson(errors)
    ))
  }, { post =>
    Post.create(post.channelId, post.message, post.datePosted, post.author)
    Ok(Json.obj("status" -> "OK", "message" -> "Post created"))
  })
}

Now, what I'm guessing that will tell you is that "5-15-2013" is not a valid date. The default date format for JSON in Play is yyyy-MM-dd. You can specify a custom one by modifying your format to say:

...
(__ \ "datePosted").format[Date](Format(Reads.dateReads("MM-dd-yyyy"), Writes.dateWrites("MM-dd-yyyy"))) and
...

Another built in one Reads.IsoDateReads, this is more standard than the American only month day year format, another approach that avoids this issue altogether is use a Long as milliseconds since epoch.

Upvotes: 2

Related Questions