Official Greenfossil Scala library to handle form submission.
This library uses sbt as its build tool. It requires at least Java 17 or later to build.
Follow the official guide on how to install sbt.
To use data-mapping, import the following package:
import com.greenfossil.data.mapping.Mapping.*
import com.greenfossil.data.mapping.Mapping
Single field mappings can be declared like below:
val textMapping = Mapping("text", text)
val nonEmptyTextMapping = Mapping("text", nonEmptyText)
val boolMapping = Mapping("bool", boolean)
val intMapping = Mapping("int", number)
val localDateMapping = Mapping("date", localDateUsing("yyyy-MM-dd"))
Mappings can also contain multiple fields:
val tupleMapping = tuple(
"text" -> text,
"date" -> localDateUsing("yyyy-MM-dd"),
"int" -> number,
"bool" -> boolean
)
Mappings can be mapped to a case class:
case class User(firstname: String, lastname: String)
val userForm = mapping[User](
"firstname" -> text,
"lastname" -> text
)
Mappings can also be defined to have repeated values
val namesForm: Mapping[Seq[String]] = Mapping("name", seq(text))
val tuplesForm: Mapping[Seq[(String, String)]] = repeatedTuple(
"firstname" -> text,
"lastname" -> text
)
case class User(firstname: String, lastname: String)
val usersForm: Mapping[Seq[User]] = repeatedMapping[User](
"firstname" -> text,
"lastname" -> text
)
A field can sometime be optional:
val optionalTextMapping: Mapping[Option[String]] = Mapping("optional", optional(text))
A field can have a default value. Default values are used when there is no corresponding data for the field from the request.
val numberMapping = Mapping("number", default(1))
val dateMapping = Mapping("date", default(localDateUsing("yyyy-MM-dd"), LocalDate.now))
A field can also be made to have a static value using ignored
case class User(id: Long, firstname: String, lastname: String)
val usersForm: Mapping[Seq[User]] = repeatedMapping[User](
"id" -> ignored(1),
"firstname" -> text,
"lastname" -> text
)
Individual fields can have constraints. By default, nonEmptyText field requires a non empty strings while text field accepts empty strings. Other fields, such as number or localDate requires the submitted data to be of a certain format.
Text fields can be defined to require a certain length:
val textMapping = Mapping("text", text(minLength = 10, maxLength = 30, trim = true))
Similarly, number fields can have min or max value:
val numberMapping = Mapping("number", number(min = 10, max = 30))]
A field can also have ad-hoc constraints:
val dobMapping = Mapping(
"dob",
localDate.verifying("Date should not be in the future", !_.isAfter(LocalDate.now))
)
Multiple fields can be verified as a whole:
val tupleMapping = tuple(
"min" -> number,
"max" -> number
).verifying("Min has to be smaller or equal to max", (min, max) => min <= max)
Fields can be transformed from one type to another.
In the example below, a comma separated text is transformed to a sequence of String.
val form: Mapping[Seq[String]] = Mapping(
"values", text.transform[Seq[String]](_.split(","), _.mkString(","))
)
You can fill the form using the fill method:
val form = Mapping("name", nonEmptyText)
form.fill("John Doe")
Data can be retrieved from the request using the bindFromRequest() method.
@Post("/submit")
def submitForm = Action{implicit request =>
form.bindFromRequest().fold(
errorForm => ???, // form errors can be obtained from errorForm.errors
data => ??? // successfully bound data
)
}
The form can also be bound manually using key-value pairs:
form.bind("firstname" -> "john", "lastname" -> "doe")
A bound form can have individual field errors.
To access the individual fields, we can use the apply methods:
val form = tuple(
"name" -> nonEmptyText.transform[String](_.capitalize, _.capitalize),
"age" -> number
)
val boundForm = form.bind("name" -> "john")
val nameValue = boundForm[String]("name").value // Some("John")
val nameBindingValue = boundForm[String]("name").bindingValue // Some("john")
val ageError = boundForm[Int]("age").errors.map(_.message) // List("error.required")
data-mapping is licensed under the Apache license version 2. See LICENSE.