Skip to content

@tindzk tindzk released this Mar 5, 2019 · 1 commit to master since this release

Release Summary 📝

Version 0.2.0 features a number of user-facing changes. Trail now has zero dependencies, supports Scala Native and has better type inference. You can follow the links below to the pull requests for more information.

Migration Steps 💻

Tuples instead HLists

Previously, route arguments were encoded using HLists:

url match {
  case Routes.index(HNil) => /// ...
  case Routes.details(id :: revision :: HNil) => // ...
}

Routes.details.url(1 :: 2 :: HNil)

Starting from v0.2.0, tuples are used instead:

url match {
  case Routes.index(()) => // ...
  case Routes.details((id, revision)) => // ...
}

Routes.details.url((1, 2))

Parsing precedence

Define two routes with the same prefix:

val route  = Root / "details"
val route2 = Root / "details" / Arg[Int]

Previously, route would only match the URL /details, but now it also matches any URL with this prefix, e.g. /details/42 or /details/a/b.

In your routing table, you will have to make sure that when matching two routes with the same prefix, the longer one has a higher precedence:

url match {
  case route2(id)) => // ...
  case route(()) => // ...
}

Optional arguments

ParamOpt[T] was dropped in favour of the more generic Param[Option[T]]. The route:

val route = Root & ParamOpt[Int]("test")

becomes:

val route = Root & Param[Option[Int]]("test")

Codecs

In v0.2.0, codecs can return optional values which will be skipped when creating the URL. Similarly, you can detect in decode() if no value was provided for an argument and return a default value.

implicit case object FooArg extends Codec[Foo] {
  override def encode(s: Foo): Option[String] = // ...
  override def decode(s: Option[String]): Option[Foo]] = // ...
}

New Features 🚀

Support fragment identifiers (#26)

Fragment identifiers are frequently used for routing in single-page applications. In Trail routes, you can specify fragments using the $ sign:

val routeFragment = Root $ Fragment[Int]
routeFragment.parse("/#42")  // Some(42)

Provide parsed route (#27)

When you use the parse() or unapply() methods, you can now provide a trail.Path() argument as opposed to a string. If you already have a deconstructed URL, this will reduce the parsing overhead:

route.parse(trail.Path("/user/hello", List("show" -> "false")))

Use tuples instead of HLists (#29)

Instead of Shapeless HLists, v0.2.0 uses tuples for encoding types of path elements.

This change resulted in better IDE support and improved type inference. For example, you can construct route arguments with Some(x) where previously Option(x) was required:

val route = Root & Param[Option[Int]]("test")
route(Some(42))  // /?test=42

Also, conditional routes are supported. In v0.1, the following route would not have type-checked:

if (isProduction) Root / "api" / "v2.0" else Root

Add Scala Native support (#30)

As a consequence of the tuple refactoring, all external dependencies could be dropped which allows us to now fully support Scala Native.

Closed issues 📕

#14, #20, #24, #25, #28

Assets 2
You can’t perform that action at this time.