Play Framework form mapping field validators (boolean, text, nonEmptyText, date, email, number, etc.)

The Play Framework scala.play.api.data.Forms object (Play 2.6) provides form validation helpers (which I've also seen referred to as mappings, data manipulation helpers, and constraints) such as these:

  • boolean
  • checked
  • date
  • email
  • ignored
  • list
  • longNumber
  • nonEmptyText
  • number
  • optional
  • seq
  • single
  • sqlDate
  • text

I couldn't find a simple list of mappings/validators like this anywhere else, so I thought I'd include them here.

Note: This is the URL for the Forms object for Play 2.2.x.

Play Framework Form Constraints/Validators

Later that same day ... I also just started to put together a little list of example Play Framework form constraints/validators, i.e., how you use these things like text, nonEmptyText, number, longNumber, email, boolean, etc. Here's what I have so far, with the initial examples coming from the Scala Forms page:

// from ScalaForms page
case class User(name: String, age: Int)
val userForm = Form(
  mapping(
    "name" -> text.verifying(required),
    "age" -> number.verifying(min(0), max(100))
  )(User.apply)(User.unapply)
)

// (1) one way to constrain/validate
"name" -> text.verifying(required),
"age" -> number.verifying(min(0), max(100))

// (2) the same validations, in a different format
"name" -> nonEmptyText,
"age" -> number(min=0, max=100)


// other examples i've put together to show how these should be used

"username" -> nonEmptyText,
"username" -> nonEmptyText(6),       // requires a minimum of six characters
"notes" -> text,
"password" -> text(minLength = 10),
"count" -> number,
"addToMailingList" -> boolean,
"email" -> email,
"company" -> optional(text),
"numberOfShares" -> optional(number),
"stocks" -> list(text),
"emailAddresses" -> list(email),
"id" -> ignored(1234),

This is a form I'm putting together for a current project. It works, though I'm intentionally validating the symbol field twice here to show two different ways it can be done, one at the field level, and the other at the form level:

val stockForm: Form[Stock] = Form(
  mapping(
    // verifying here creates a field-level error
    // if your test returns false, the error is shown
    "symbol" -> nonEmptyText.verifying("Doh - Stock already exists (1)!", Stock.findBySymbol(_) == 0),
    "company" -> optional(text))
    ((symbol, company) => Stock(0, symbol, company))  // apply
    ((s: Stock) => Some((s.symbol, s.company)))       // unapply
    verifying("Doh - Stock already exists (2)!", fields => fields match {
      // this block creates a form-level error.
      // this only gets called if all field validations are okay. as shown, this will never get
      // called b/c the field-level validator catches the same error.
      case Stock(i, s, c) =>  Stock.findBySymbol(s) == 0
    })
)

That's pretty ugly with all the comments, so here's the same code with the comments removed, and one minor formatting change:

val stockForm: Form[Stock] = Form(
  mapping(
    "symbol" -> nonEmptyText.verifying("Doh - Stock already exists (1)!", Stock.findBySymbol(_) == 0),
    "company" -> optional(text))
    ((symbol, company) => Stock(0, symbol, company))
    ((s: Stock) => Some((s.symbol, s.company))
  ) verifying("Doh - Stock already exists (2)!", fields => fields match {
      case Stock(i, s, c) =>  Stock.findBySymbol(s) == 0
    })
)

That's still a bit ugly, but now that I understand Play a little better, I believe it can be cleaned up, at least the 'apply' and ‘unapply’ portions.