JS client of rest api can send both int and string as a value of some field.
{
field1: "123",
field2: "456"
}
{
field1: 123,
field2: 456
}
Here is play action with case class to which json request body should be converted:
case class Dto(field1: Int, field2: Int)
object Dto {
implicit val reads = Json.reads[Dto]
}
def create = Action.async(BodyParsers.parse.json) { implicit request =>
request.body.validate[Dto].map {
dto => someService.doStuff(dto).map(result => Ok(Json.toJson(result)))
}.recoverTotal {
e => jsErrorToBadRequest(e)
}
}
In case if I send json values with int values, it works ok. But in case if field1 or field2 are strings ("123", "456"), it fails, because request.body.validate expects Int.
But problem is that JS client sends values from input fields, and input fields are converted to strings.
What is the best way to handle either ints or strings? (So this action should convert json to dto in both cases)
You could also define a more tolerant Reads[Int]
.
And use it to define your Reads[Dto]
1) Define a more tolerant Reads[Int]
:
import play.api.data.validation.ValidationError
import play.api.libs.json._
import scala.util.{Success, Try}
// Define a more tolerant Reads[Int]
val readIntFromString: Reads[Int] = implicitly[Reads[String]]
.map(x => Try(x.toInt))
.collect (ValidationError(Seq("Parsing error"))){
case Success(a) => a
}
val readInt: Reads[Int] = implicitly[Reads[Int]].orElse(readIntFromString)
Examples:
readInt.reads(JsNumber(1))
// JsSuccess(1,)
readInt.reads(JsString("1"))
// JsSuccess(1,)
readInt.reads(JsString("1x"))
// JsError(List((,List(ValidationError(List(Parsing error),WrappedArray())))
2) Use your more tolerant Reads[Int]
to define your Reads[Dto]
:
implicit val DtoReads =
(JsPath \ "field1").read[Int](readInt) and
(JsPath \ "field2").read[Int](readInt)
EDIT: Differences with millhouse's solution:
if field1
is a string and field2
is an int with this solution you'll get a JsSuccess
but a JsError
with millhouse's solution
If both field are invalid with this solution you'll get a JsError
containing one error for each field. With millhouse's solution you'll get the first error.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With