3

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.

1
  • What does the entry in your routes file look like for this method? Commented Nov 7, 2013 at 21:45

1 Answer 1

2

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.