Play + Scala -> 验证 IP Json 数据

Play + Scala -> Validate IP Json data

我正在尝试在 Play Controller 中验证 POST 请求中的 JSON 负载。我是 Play & Scala 世界的新手。

下面的代码是我目前得到的。这在没有任何输入验证的情况下工作正常。现在我正在尝试将验证添加到 IPRangeStr class 和 运行 上的 IP 地址字段到问题中。我无法弄清楚对包含枚举的 json 列表的验证。

谢谢

object listTypes extends Enumeration {
  type listTypes = Value
  val TypeA= Value("TypeA")
  val TypeB = Value("TypeB")
  val Unknown = Value("Unknown")

  def withNameWithDefault(name: String): Value =
    values.find(_.toString.toLowerCase == name.toLowerCase()).getOrElse(Unknown)
}

case class IPRangeStr(firstIP: String, lastIP: String, listType: listTypes, action: String)


@Singleton
class DataController @Inject()(cc: ControllerComponents, actorSvc: IPDataActorService)(implicit exec: ExecutionContext) extends AbstractController(cc) {

  implicit val listTypeEnumFormat = new Format[listTypes.listTypes] {
    def reads(json: JsValue) = JsSuccess(listTypes.withNameWithDefault(json.as[String]))
    def writes(listEnum: listTypes.listTypes) = JsString(listEnum.toString)
  }

  implicit val ipRangeStrReads: Reads[IPRangeStr] = Json.format[IPRangeStr]
  implicit val ipRangeStrWrites = Json.writes[IPRangeStr]

  def process = Action.async(parse.json[List[IPRangeStr]]) { implicit request =>
   if(validationSuccess){    
        // process if validation successfull 
        Ok 
      } else {
        BadRequest // validation error
      }
    } recoverWith {
      case e: Exception  =>
        Future(InternalServerError)
    }
  }
}

#Edit-1 我的最终解决方案基于@cchantep ans

val validIPPattern: String = "(([01]?\d\d?|2[0-4]\d|25[0-5])\.){3}([01]?\d\d?|2[0-4]\d|25[0-5])"

def isValidIP(ip:String) = ip.matches(validIPPattern)

implicit val ipRangeStrReads: Reads[IPRangeStr] =
    Json.format[IPRangeStr].filter { ipR =>
      isValidIP(ipR.firstIP) && isValidIP(ipR.lastIP)  //true  or false, according validation of ipR
}     

implicit val ipRangeStrWrites = Json.writes[IPRangeStr]

When using Json.format, is not required to have a second call to Json.write for the same type, as OFormat is able to read and write.

如果我删除我的写入,当我将对象转换为 Json 字符串时,我的控制器会出现异常。

尝试为此类型实现隐式写入或格式。

I would rather use enumNameReads and enumNameWrites.

很高兴知道这一点 shorthand。我最终使用我以前的解决方案,在转换为枚举之前将 json 字符串转换为小写。

It's recommended to name type with an initial cap, without final "s" for plural (e.g. ListType).

这点我完全同意。不幸的是,它是我现在不想重构的遗留代码的一部分。

作为 monadic 类型,函数 .filter 可用于 Reads

implicit val ipRangeStrReads: Reads[IPRangeStr] =
  Json.format[IPRangeStr].filter { ipR =>
    true // or false, according validation of ipR
  }

When using Json.format, is not required to have a second call to Json.write for the same type, as OFormat is able to read and write.

我宁愿使用 enumNameReadsenumNameWrites

implicit val r = Reads.enumNameReads(listTypes)
implicit val w = Writes.enumNameWrites[listTypes.type]

It's recommended to name type with an initial cap, without final "s" for plural (e.g. ListType).