Handy Scala macros for everyday use: Route, Wither.
Scala 2.13 only!
ScalaJS 1 is supported.
Generates apply/unapply methods for extracting/constructing URLs. Here's why:
- type safe URLs/routes
- unlike Play SIRD and others, it can also construct a URL
In Play, Angular and other frameworks you'd write something like this:
/users/:id/:name ? minAge=:minAge & qs=:qs...
With @Route
macro you write this:
@Route
class UsersRoute( /* first list contains path params */
p1: "users", // fixed
val id: Long, // variable
val name: String
)( /* second list contains query params (those after ?) */
val minAge: Int, // mandatory
val opt: Option[Int], // optional
val qs: Set[String] // multi-valued
)
// construct a URL, type-safely
val route = UsersRoute(1, "Sake")(123, Some(456), Set("q1"))
val redirectUrl = route.urlData.url // /users/1/Sake?minAge=18&opt=456&qs=q1
// deconstruct a string URL to type-safe data
"users/1/Sake?minAge=123&qs=q1&qs=q2&opt=456" match {
case UsersRoute(id, name, minAge, opt, qs) =>
println(s"$id, $name, $minAge, $opt, $qs") // 1, Sake, 123, Some(456), Set(q1, q2)
case _ => println("404 Not Found")
}
Regex is supported, just put it inside angle brackets:
@Route class RegexRoute(p1: "users", val name: "<[a-z]+>")
This would match a string /users/tom
, but not /users/Tom
.
You can match on multi-segment path with a *
:
@Route class StarRoute(p1: "files", val path: "*")
This would match a string /files/images/abc.jpg
etc.
Basically, anything starting with /files
...
Generates with*
methods. Here's why:
- more readable than named args
- autocomplete is nicer
- additional
with
ers forOption
,List
etc
If you have this:
@Wither
class MyClass(
simple: Int,
opt: Option[Int],
list: List[Int]
)
you get to write:
val data = new ExampleData(1, Some(10), List(100))
data.withSimple(2) // MyClass(2, Some(10), List(100))
data.withOpt(Some(11)) // MyClass(2, Some(11), List(100))
data.withOpt(12) // MyClass(2, Some(12), List(100))
data.withList(List(101, 102)) // MyClass(7, None, List(101,102))
data.withList(103, 104) // MyClass(7, None, List(103,104))
data.withSimple(2).withOpt(12).withList(103, 104) // MyClass(2, Some(12), List(103,104))