{"id":21569889,"url":"https://github.com/iterable/iterable-play-utils","last_synced_at":"2025-10-06T19:40:28.694Z","repository":{"id":57725416,"uuid":"60741788","full_name":"Iterable/iterable-play-utils","owner":"Iterable","description":"Iterable's Utilities for Play Framework for Scala","archived":false,"fork":false,"pushed_at":"2025-02-06T20:04:58.000Z","size":50,"stargazers_count":11,"open_issues_count":3,"forks_count":0,"subscribers_count":68,"default_branch":"master","last_synced_at":"2025-03-24T12:56:19.420Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Scala","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Iterable.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-06-09T01:17:43.000Z","updated_at":"2025-02-06T20:04:59.000Z","dependencies_parsed_at":"2024-11-24T11:11:03.670Z","dependency_job_id":"805b0c47-9cd2-4f14-a9ca-312e742ad0c6","html_url":"https://github.com/Iterable/iterable-play-utils","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Iterable%2Fiterable-play-utils","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Iterable%2Fiterable-play-utils/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Iterable%2Fiterable-play-utils/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Iterable%2Fiterable-play-utils/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Iterable","download_url":"https://codeload.github.com/Iterable/iterable-play-utils/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248232618,"owners_count":21069487,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-24T11:10:58.399Z","updated_at":"2025-10-06T19:40:23.629Z","avatar_url":"https://github.com/Iterable.png","language":"Scala","readme":"# iterable-play-utils\n\n[![Travis CI](https://github.com/iterable/iterable-play-utils/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/iterable/iterable-play-utils/actions/workflows/ci.yml) [![Maven](https://img.shields.io/maven-central/v/com.iterable/iterableplayutils_2.12.svg)](https://mvnrepository.com/artifact/com.iterable/iterableplayutils)\n\nA collection of utilites used by Iterable in Scala Play! projects.\n\n## Adding to your SBT project\n\nThe latest version supports Play 2.8.x. To include it in your dependencies:\n\n```scala\nlibraryDependencies += \"com.iterable\" %% \"iterableplayutils\" % \"4.0.0\"\n```\n\nAll versions can be found on [maven central](https://mvnrepository.com/artifact/com.iterable/iterableplayutils).\n\n\nVersion | Scala version | Play! version\n--- | --- | ---\n4.0.0 | 2.13.x/2.12.x | 2.8.x\n3.0.0 | 2.13.x/2.12.x | 2.7.x\n2.0.0 | 2.12.x/2.11.x | 2.6.x\n1.1.1 | 2.11.x | 2.5.x\n1.1.0 | 2.11.x | 2.4.x\n1.0.1 | 2.10.x | 2.2.x\n\n## Automatic Case Class Mappings (via runtime reflection)\n\nSee [com.iterable.play.utils.CaseClassMapping](https://github.com/Iterable/iterable-play-utils/blob/master/src/main/scala/com/iterable/play/utils/CaseClassMapping.scala). Uses ***runtime reflection*** to generate form mappings for case classes without all the manual typing.\n\n***Once again, this uses runtime reflection, not compile-time macros.***\n\nSuppose you have the following case class:\n```scala\ncase class Foo(\n  bar: String,\n  baz: Option[Long]\n)\n```\n\nIn order to use forms/mappings, you would normally do:\n```scala\nval fooForm = Form(\n  mapping(\n    \"bar\" -\u003e text,\n    \"baz\" -\u003e optional(longNumber)\n  )(Foo.apply)(Foo.unapply)\n)\n```\n\nThis works fine, but it can get very cumbersome if your case classes take many parameters. It's also difficult to keep track of things if you rename the various arguments. `CaseClassMapping` seeks to take care of this by automatically generating a `Mapping[T]` for your case class `T`. In order to use it, any non-standard types that your case class uses must expose an `implicit Mapping[T]` of that type in their companion object; additionally, that mapping must be either a `nullary def` or a `val`.\n\nFor example, to create a form for our example `case class Foo`, you can do:\n```scala\nval fooForm = Form(CaseClassMapping.mapping[Foo])\n```\n\n...and that's it!\n\nMore often we use it like this:\n```scala\nobject Foo {\n  implicit val mapping = CaseClassMapping.mapping[Foo]\n}\n\n// somewhere later where we need a Form[Foo]\nval fooForm = Form(implicitly[Mapping[Foo]])\n```\n\nIf you want to add constraints to your mapping, you can still do so; for example, if we want to make sure that `Foo.bar` is at least 5 characters long:\n```scala\nobject Foo {\n  implicit val mappingWithConstraint = CaseClassMapping.mapping[Foo].verifying {\n    Constraint[Foo](\"Foo.bar\") { foo =\u003e\n      Constraints.minLength(5)(foo.bar)\n    }\n  }\n}\n```\n\nAnother use case for this is for posting form data via Play's `WS`. Normally, you would do something like this:\n```scala\nWS.url(\"https://some.api.expecting.form.encoded.data\").post(\n    Map(\n        \"name\" -\u003e Seq(\"ilya\"),\n        \"age\" -\u003e Seq(9001.toString),\n        \"email\" -\u003e Seq(\"ilya at iterable dot com\"),\n        \"favoriteBands\" -\u003e Seq(\"Judas Priest\", \"Accept\")\n    )\n)\n```\n\nThat doesn't look particularly nice... so you can use `UnbindableToWsRequest`:\n```scala\ncase class User(name: String, age: Int, email: String, favoriteBands: Seq[String]) extends UnbindableToWsRequest[User]\nobject User {\n    implicit val mapping = CaseClassMapping.mapping[User]\n}\n\nval user = User(name = \"ilya\", age = 9001, email = \"ilya at iterable dot com\", favoriteBands = Seq(\"Judas Priest\", \"Accept\"))\nWS.url(\"some url\").post(user.unbindToWsRequest)\n```\n\nNote that there is one caveat with this; `Seq` types. Using the previous example, the unbound data will look like this:\n```scala\nMap(\n    \"name\" -\u003e Seq(\"ilya\"),\n    \"age\" -\u003e Seq(9001.toString),\n    \"email\" -\u003e Seq(\"ilya at iterable dot com\"),\n    \"favoriteBands[0]\" -\u003e Seq(\"Judas Priest\"),\n    \"favoriteBands[1]\" -\u003e Seq(\"Accept\")\n)\n```\n\nSpecifically, note that `favoriteBands` is unbound as\n```scala\n    \"favoriteBands[0]\" -\u003e Seq(\"Judas Priest\"),\n    \"favoriteBands[1]\" -\u003e Seq(\"Accept\")\n```\n\ninstead of\n```scala\n    \"favoriteBands\" -\u003e Seq(\"Judas Priest\", \"Accept\")\n```\n\nSee [the tests](https://github.com/Iterable/iterable-play-utils/blob/master/src/test/scala/com/iterable/play/utils/CaseClassMappingSpec.scala) for more sample usage.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fiterable%2Fiterable-play-utils","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fiterable%2Fiterable-play-utils","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fiterable%2Fiterable-play-utils/lists"}