Play framework and Validation

Play framework and Validation

In our API, we handle JSON format request body, some path parameters, some query parameters.

In play framework, we use JSON implicit methods to validation the input JSON request body. For path parameters, I validate it in my actions in controllers.

Here is how I do it.

  /* basic */
  implicit val jodaDateWrites = Writes.dateWrites("yyyy-MM-dd'T'HH:mm:ssXXX")
  implicit val jodaDateReads = Reads.dateReads("yyyy-MM-dd'T'HH:mm:ssXXX")

  implicit val LocationWrites = Json.writes[Location]
  implicit val LocationReads: Reads[Location] = (
      (JsPath \ "addressLine1").readNullable[String] and
        (JsPath \ "addressLine2").readNullable[String] and
        (JsPath \ "city").readNullable[String] and
        (JsPath \ "state").readNullable[String] and
        (JsPath \ "country").readNullable[String] and
        (JsPath \ "postalCode").readNullable[String] and
        (JsPath \ "latitude").readNullable[String] and
        (JsPath \ "longitude").readNullable[String]
      )(Location.apply _)

  implicit val JobPostBudgetRequestReads: Reads[JobPostBudgetRequest] = {
    (
      (JsPath \ "budget").read[BigDecimal] and
      (JsPath \ "budgetType").read[String](Reads.minLength[String](1)) and
      (JsPath \ "cpaPrice").read[BigDecimal](Reads.min(BigDecimal.apply(0.01)))
    )(JobPostBudgetRequest.apply _)
  }

  implicit val JobPostDetailRequestReads: Reads[JobPostDetailRequest] = (
      (JsPath \ "accountID").readNullable[String] and
        (JsPath \ "referenceID").read[String](Reads.minLength[String](1)) and
        (JsPath \ "title").read[String](Reads.minLength[String](1)) and
        (JsPath \ "description").read[String](Reads.minLength[String](1)) and
        (JsPath \ "companyName").readNullable[String] and
        (JsPath \ "locations").read[Seq[Location]] and
        (JsPath \ "startTime").readNullable[Date] and
        (JsPath \ "stopTime").readNullable[Date] and
        (JsPath \ "emailAddress").read[String](Reads.minLength[String](1)) and
        (JsPath \ "hostedByJ2C").read[Boolean] and
        (JsPath \ "applyURL").read[String](Reads.minLength[String](1)) and
        (JsPath \ "requireResume").read[Boolean]
      )(JobPostDetailRequest.apply _)

  implicit val JobStatusRequestReads: Reads[JobStatusRequest] = (
    (JsPath \ "status").read[String](Reads.minLength[String](4) keepAnd Reads.maxLength[String](7)).map(
      JobStatusRequest.apply _)
    )

  implicit val JobPostRequestReads: Reads[JobPostRequest] = (
        (JsPath \ "jobDetail").read[JobPostDetailRequest] and
        (JsPath \ "jobBudget").read[JobPostBudgetRequest]
      )(JobPostRequest.apply _)

First of all, when we define the scala case class to matching with the JSON format, Option make this parameter optional. And in this implicit file, we define something like Reads.minLength[String](4) or some other requirements. That is the validation when we doing the JSON parse.

In the controller, sometimes we handle the JSON parse validation like this and we do further validation as well.

val obj = request.body.validate[JobDetailUpdateRequest]
    obj.fold(
      errors => {
        BadRequest(Json.toJson(new ErrorResponse("INVALID_JSON_REQUEST", "Bad JSON request parameters.", JsError.toJson(errors).toString())))
      },
      jobDetailUpdateRequest => {
            logger.trace("Param validation success, param = " + jobDetailUpdateRequest)

            jobDetailUpdateRequest.emailAddress match {
              case Some(e) if !checkEmail(e)=> {
                BadRequest(Json.toJson(new ErrorResponse("INVALID_EMAIL_ADDRESS", "emailAddress invalid " + e + " .", "")))
              }
              case _ => {
                try{
                  val jobResponse = JobOldService.updateJob(campaignID, jobDetailUpdateRequest)
                  jobResponse match {
                    case Some(res) => Ok(Json.toJson(res))
                    case _ => { NotFound(Json.toJson(new ErrorResponse(
                      "RESOURCE_NOT_FIND",
                      "Can not find the resource with campaignID = " + campaignID + " referenceID = " + referenceID,
                      "")
                    ))
                    }
                  }
                }catch{
                  case ex:Exception => {
                    InternalServerError(Json.toJson(new ErrorResponse("SERVER_ERROR", "", ex.getMessage)))
                  }
                }
              }
            }
      }
    )

checkEmail is the customized validation I implement myself.

References:
https://www.playframework.com/documentation/2.4.x/ScalaJsonCombinators

猜你喜欢

转载自sillycat.iteye.com/blog/2286364