Skip to content

Finch 0.23

Compare
Choose a tag to compare
@vkostyukov vkostyukov released this 09 Aug 23:21
· 772 commits to master since this release
00d0ca2

This new Finch release, while matching Finagle 18.8, comes with several quite exciting improvements.

Multiple Decoders for Bodies

We've been asked if it's possible to specify multiple decoders (in a sense of or application) to a single body endpoint. Similar how users can serve multiple content-types based on the Accept header value, they now can resolve multiple decoders at compile-time and dispatch to an appropriate decoder at runtime when a request with the Content-Type header arrives (see #966 for implementation details; thanks @sergeykolbasov).

scala> import io.finch._, com.twitter.util._, com.twitter.io.Buf, shapeless._

scala> :paste
// Entering paste mode (ctrl-D to finish)

case class Foo(s: String)
object Foo {
  implicit val d1 = Decode.instance[Foo, Text.Plain]((_, _) => Return(Foo("text")))
  implicit val d2 = Decode.instance[Foo, Text.Html]((_, _) => Return(Foo("html")))
}

^D

scala> val foo = body[Foo, Text.Plain :+: Text.Html :+: CNil]
foo: io.finch.Endpoint[Foo] = body

scala> foo(Input.post("/").withBody[Text.Plain](Buf.Utf8("foo"))).awaitValueUnsafe()
res5: Option[Foo] = Some(Foo(text))

scala> foo(Input.post("/").withBody[Text.Html](Buf.Utf8("foo"))).awaitValueUnsafe()
res6: Option[Foo] = Some(Foo(html))

Arrows instead of Rerunnables

We've been experimenting with Trane Arrows as a drop-in replacement for Finch's underlying effect, Rerunnable. The results are quite uplifting considering the performance improvements gained without visible API changes.

Here is a sneak peek into the performance improvements (see #964 for more details; thanks @erikwj).

BEFORE (Rerunnable)

[info] Benchmark                                                   Mode  Cnt     Score     Error   Units
[info] ProductBenchmark.bothMatched                                avgt   10   984.884 ±  35.849   ns/op
[info] ProductBenchmark.bothMatched:·gc.alloc.rate.norm            avgt   10  1472.000 ±   0.001    B/op

AFTER (Arrow/Task)

[info] ProductBenchmark.bothMatched                                avgt   10   361.867 ±   8.955   ns/op
[info] ProductBenchmark.bothMatched:·gc.alloc.rate.norm            avgt   10   712.000 ±  12.749    B/op

We published Finch depending on Arrows (instead of Rerunnables) under its own artifact for now for the sake of keeping the standard version unchanged. We are aiming to collect more feedback from users before we decide to adopt/not adopt. Use the following dependency (finch-arrows-x instead of finch-x) to experiment with Arrows (no source changes required) and let us know what do you think in #968.

libraryDependencies ++= Seq(
  "com.github.finagle" %% "finch-arrows-core" % "0.23.0",
  "com.github.finagle" %% "finch-arrows-circe" % "0.23.0",
)

Other Changes