Changelog History
-
v0.32.1 Changes
March 11, 2020Hello Scala 2.13, bye 2.11
๐ Long-awaited release for Scala 2.13 has finally arrived. Thanks for your patience as well as for all the efforts the community has made to update Finagle to 2.13.
โฌ๏ธ We also drop the support for Scala 2.11, as some of the dependencies aren't available for that version.
๐ Last release of
finchx
artifacts. Long live thefinch
๐ This release is expected to be the last one for
finchx
prefixed artifacts. Starting from the next update we're going to decommission theFuture
-basedfinch
artifacts and replace it with polymorphic one.
โก๏ธ Effectively, it means that nofinchx
artifacts will be updated and you would need to update the dependency by dropping thex
letter.๐ To ensure the best developer experience we're going to groom existing documentation to make it up to date with all the exciting changes and capabilities of Finch.
๐ Release notes
-
v0.32.0 Changes
March 10, 2020๐ See 0.32.1
-
v0.31.0 Changes
September 05, 2019 -
v0.30.0 Changes
August 19, 2019๐ This is a release of Finch with Finagle 19.6.0.
๐ In addition to version bumps of many libraries, this release has the following:
- ๐ Removal of the deprecated
transformOutput
- ๐ Removal of the deprecated
-
v0.29.0 Changes
May 18, 2019๐ A release for Finagle 19.4, the first release without Netty 3 on the classpath!
In addition to version bumps, here are the notable changes:
-
v0.28.0 Changes
February 27, 2019๐ This release introduces new functionality to build a middleware of your HTTP service.
Kleisli composition
Instead of converting
Endpoint
straight intoService[Request, Response]
, there is now an option to compile it first intoKleisli[F[_], Request, (Trace, Either[Throwable, Response])]
data type (orEndpoint.Compiled[F]
as a type alias). It allows to replace most of the Finagle filters with Kleisli composition that is also effect-aware:finch@ import cats.effect.IOimport cats.effect.IOfinch@ import cats.data.Kleisliimport cats.data.Kleislifinch@ import io.finch.\_import io.finch.\_finch@ import io.finch.catsEffect.\_import io.finch.catsEffect.\_finch@ val endpoint = get("hello") { Ok("world") } endpoint: Endpoint[IO, String] = GET /hello finch@ val compiled = Bootstrap.serve[Text.Plain](endpoint).compile compiled: Endpoint.Compiled[IO] = Kleisli(io.finch.Compile$$anon$2$$Lambda$2951/1251806319@7dccca17) finch@ val authFilter = Kleisli.ask[IO, Request].andThen { req =\>if(req.authorization.isEmpty) IO.raiseError(new IllegalStateException()) else IO.pure(req) } authFilter: Kleisli[IO, Request, Request] = Kleisli(cats.data.Kleisli$$$Lambda$2999/1785722147@b53898c) finch@ val finale = authFilter.andThen(compiled) finale: Kleisli[IO, Request, (Trace, Either[Throwable, com.twitter.finagle.http.Response])] = Kleisli(cats.data.Kleisli$$$Lambda$2999/1785722147@7c51944f) finch@ val service = Endpoint.toService(finale) service: com.twitter.finagle.Service[Request, com.twitter.finagle.http.Response] = ToService(Kleisli(cats.data.Kleisli$$$Lambda$2999/1785722147@7c51944f)) finch@ service(Request("/hello")) res38: com.twitter.util.Future[com.twitter.finagle.http.Response] = Promise@471126862(state=Done(Throw(java.lang.IllegalStateException))) finch@ val req = Request("/hello") req: Request = Request("GET /hello", from 0.0.0.0/0.0.0.0:0) finch@ req.authorization = "user:password"finch@ service(req) res41: com.twitter.util.Future[com.twitter.finagle.http.Response] = Promise@1914269162(state=Done(Return(Response("HTTP/1.1 Status(200)"))))
๐ Finch will do its best to prevent
F[_]
from having an exception inside of compiled Endpoint and have it inside of the Either. Check out proper example how to build and compose filters together.๐จ Endpoint.transformF and type classes refactoring
๐ We've made a small refactoring over the Finch codebase to use as least powerful abstractions for effect
F[_]
as possible. Now, in most of the places it's enough to haveSync
orAsync
type classes available to build endpoints. It enables the use of things likeStateT
,Kleisli
, andWriterT
as your effect type, thus propagating the data down the line using the effect. More examples and documentation on this later.๐ AsyncStream deprecation
๐
asyncBody
deprecation cycle is over, consider to use fs2 or iteratee as a replacement in case if you need a streaming. Both of them are supported by corresponding Finch modules. Here is the simple example of how to use one.
Also, finch-sse was removed as a separate module. Related code moved to the core and finch-fs2 & finch-iteratee modules.Join our community
๐ If you have any questions or ideas, feel free to address them in issues or join our gitter channel.
-
v0.27.0 Changes
January 13, 2019๐ This new release is featuring fs2 integration as well fully reworked streaming support, allowing for easier testing of streaming endpoints.
๐ FS2 Support
๐ #1042 adds fs2 support in Finch (thanks @sergeykolbasov). As of 0.27, it's now possible to receive and send JSON (or pretty much any arbitrary) streams using fs2's
Stream
type. The new API entry point,bodyStream
, allows to construct streaming endpoints with the requested stream type,Enumerator
(iteratee) orStream
(fs2).scala\> import fs2.Stream, io.finch.\_, io.finch.catsEffect.\_, io.finch.fs2.\_scala\> val bin = binaryBodyStream[Stream] // raw byte-array streambin: Endpoint[IO, fs2.Stream[IO, Array[Byte]]] = binaryBodyStream scala\> val str = stringBodyStream[Stream] // stream of stringsstr: Endpoint[IO, fs2.Stream[IO, String]] = stringBodyStream
Similarly, accepting a stream of JSON object is possible via
bodyStream
orjsonBodyStream
endpoints.scala\> import fs2.Stream, io.finch.\_, io.finch.catsEffect.\_, io.finch.fs2.\_scala\> import io.finch.circe.\_, io.circe.generic.auto.\_scala\> case class Foo(s: String) defined class Fooscala\> val foos = bodyStream[Stream, Foo, Application.Json] foos: Endpoint[IO,f s2.Stream[IO, Foo]] = bodyStream scala\> val foos = jsonBodyStream[Stream, Foo] foos: Endpoint[IO, fs2.Stream[IO, Foo]] = bodyStream
๐ฐ Serving streaming bodies is no different from serving fully-buffered payloads, just return
Stream
(fs2) orEnumerator
from an endpoint.scala\> import fs2.Stream, cats.effect.IO, io.finch.\_, io.finch.catsEffect.\_, io.finch.fs2.\_scala\> import io.finch.circe.\_, io.circe.generic.auto.\_scala\> case class Foo(s: String) defined class Fooscala\> val foos = Endpoint[IO].const(Stream[IO, Foo](Foo("bar"))) foos: Endpoint[IO, fs2.Stream[IO, Foo]] = io.finch.Endpoint$$anon$34@5428e82e scala\> foos.toServiceAs[Application.Json] res1: Service[Request, Response] = io.finch.ToService$$anon$4$$anon$2
โ Testing Streaming Endpoints
๐ #1056 enables users to construct
Input
instances with streaming bodies (non fully buffered). At this point, both fs2 and iteratee streams are supported.import io.finch.\_, io.finch.iteratee.\_, io.interatee.Enumerator, cats.effect.IOval i = Input .post("/") .withBody[Text.Plain](Enumerator.enumerate[IO, String]("foo", "bar", "baz"))
Creating an
Input
out of a JSON stream is also possible:import io.finch.\_, io.finch.iteratee.\_, io.interatee.Enumerator, cats.effect.IOimport io.finch.circe.\_, io.circe.generic.auto.\_case class Foo(s: String)val i = Input .post("/") .withBody[Application.Json](Enumerator.enumerate[IO, Foo](Foo("foo"), Foo("bar")))
Switching between iteratee and fs2 is as easy as replacing
io.finch.iteratee._
import withio.finch.fs2._
.โก๏ธ Dependency Updates
-
v0.26.1 Changes
December 05, 2018๐ ๐Bugfix release:
- ๐ป
Endpoint.rescue
was incorretly throwingMatchError
if the exception inside of an effect was not defined for the given partitial function. The correct behavior is to re-raise the exception. This bug affected onlyfinchx-
modules. #1048
- ๐ป
-
v0.26.0 Changes
November 15, 2018๐
finch-*
Release (Twitter Futures)- โก๏ธ We have updated to Twitter Utils and Finagle 18.11.0
๐
finchx-*
Release (Cats Effect)โก๏ธ Backwards Compatibility Updates
๐ One of the biggest concerns with moving to cats-effect in 0.25 was the lack of backwards compatibility with existing
Future
-based endpoints (both Scala and Twitter implementations). This version eases that transition by adding support for both Scala and Twitter futures in the Mapper. See #1016 for more details.scala\> import io.finch.\_, io.finch.catsEffect.\_scala\> import com.twitter.util.Futurescala\> val foo = get(pathEmpty) { Future.value(Ok("foo")) } \<console\>:18: warning: method mapperFromFutureOutputValue in trait HighPriorityMapperConversions is deprecated (since 0.25.0): com.twitter.util.Future use is deprecated in Endpoints. Consider to use cats-effect compatible effect val foo = get(pathEmpty) { Future.value(Ok("foo")) } ^ foo: io.finch.Endpoint[cats.effect.IO,String] = GET /
NOTE: The
foo
endpoint is still structured asEndpoint[cats.effect.IO, String]
. Both Scala and Twitter Futures are converted to IO when endpoints are mapped.๐ Stewarding a better Environment
๐ In the past, we've gotten a fair number of Github issues and Gitter messages about getting dependencies up to date. With this release we have enabled Scala Steward which makes PRs to update versions of dependencies. A huge thanks to @fthomas for creating this tool and to @travisbrown for adding this to our main repository. We are looking into adding it into our other repositories from the Finch Org.
๐ฑ Serving Static Assets
๐ We're not about telling you not to do something with Finch, only that you can do things with Finch. In this vein, you probably shouldn't serve static assets from the classpath or a file from Finch (or really any HTTP library that isn't designed for serving static assets). But we've added
Endpoint.classpathAsset
andEndpoint.filesystemAssert
that let you do just that. Please, try not to use this in a production environment as it will never match the throughput of what static server. See #1017 for more details.scala\> import io.finch.\_, io.finch.catsEffect, scala\> import cats.effect.{IO, ContextShift} scala\> import scala.concurrent.ExecutionContextscala\> implicit val S: ContextShift[IO] = IO.contextShift(ExecutionContext.global)S: cats.effect.ContextShift[cats.effect.IO] = cats.effect.internals.IOContextShift@641d5285 scala\> val index = classpathAsset("/index.html") index: io.finch.Endpoint[cats.effect.IO,com.twitter.io.Buf] = GET /index.html :: io.finch.endpoint.package$FromInputStream@63905eda scala\> index.toServiceAs[Text.Html] res3: com.twitter.finagle.Service[com.twitter.finagle.http.Request,com.twitter.finagle.http.Response] = io.finch.ToService$$anon$4$$anon$2
Gitter8
We now have a basic gitter8 template to get new projects started fast (thanks to @vkostyukov). Just run
sbt new finch/finch.g8
to get started.Other Changes
- ๐
Endpoint
now has anpathEmpty
method which matches an empty path string (see #1015) - โก๏ธ We have updated to Twitter Utils and Finagle 18.11.0 (see #1033)
- ๐ Our version badge now points at Scala Index (see #1010)
- ๐
Endpoint.pathAny
now properly captures the matchedTrace
(see #1017) - ๐ We refined our Todo App example with the new shiny UI and tests (see #1020)
-
v0.25.0 Changes
October 21, 2018๐ Our anniversary 50th release brings a lot of exciting changes. The biggest news is starting with 0.25 (this release) Finch is now completely agnostic to the underlying effect type (was Twitter Future before).
Polymorphic Endpoints
This is, perhaps, the biggest change in Finch since introduction of
Endpoint
couple of years back. Locking our core APIs to a particular effect type (Twitter Future) never felt right yet, surely, was a reasonable thing to do at first. As Finch's API matured, we figured the major source of complains from our users was about this hard dependency to a Twitter's stack (think Twitter Util's).๐ With the 1.0 release of cats-effect, it became clear that Finch's path towards better interoperability with the rest of typelevel libraries (think Cats-based libraries) was adopting
Effect
type classes in theEndpoint
API.Long story short
Endpoint[A]
now becomesEndpoint[F[_], A]
whereF[_]
is anything that has ancats.effect.Effect
instance (think ZIO, Monix Task, Cats IO, Catbird Rerunnable, etc). This heroic effort was driven by @sergeykolbasov in #979.๐ This sounds scary at least - a LOT of API changes. To mitigate the impact we keep releasing normal Finch artifacts (Twitter Futures) under a previous name:
finch-*
. This means you don't really have to migrate to a new endpoint API just now. The current plan is to keep supporting a previous version of Finch API for some time (at least 6 months) but keep its branch under feature freeze (commit only bug-fixes and dependency bumps).If you're feeling adventurous, you can jump into polymorphic endpoints now by depending on
finchx-*
artifacts instead.libraryDependencies ++= Seq( "com.github.finagle" %% "finchx-core" % "0.25.0", "com.github.finagle" %% "finchx-circe" % "0.25.0", )
๐ There several ways how to instantiate polymorphic endpoints (see #988). Perhaps, the most standard way is via importing
io.finch.catsEffect._
EndpointModule
(in case if you prefer Cats IO as your effect type).import io.finch.\_import io.finch.catsEffect.\_val p: Endpoint[IO, Int] = param[Int]("foo")
You can also specify the
F[_]
type constructor explicitly should you prefer other effect implementation.import io.finch.\_val p: Endpoint[MyIO, Int] = Endpoint[MyIO].param[Int]("foo")
Or via instantiating an
EndpointModule
for your effect instance.import io.finch.\_object myIO extends Endpoint.Module[MyIO]import myIO.\_val p: Endpoint[MyIO, Int] = param[Int]("foo")
Notable Changes Accommodating cats-effect Integration
- ๐ฆ Syntax Package became obsolete (do not need to import it) as we can now derive syntax based on
Effect
instance. - As we're no longer depending on Twitter Futures, other Twitter APIs (
Duration
,Try
) have been migrated to their Scala's counterparts.
๐ Performance
๐ We did some initial testing of new endpoints and the outcome looks optimistic. Essentially, we're observing similar performance gains as we did with Trane Arrows couple of releases back.
๐ Auto Releases
๐ Inspired by how Trane Arrows's build is setup, @arron-green kicked in a new releasing machinery for Finch. Now we can cut releases via a single commit that changes the
version.sbt
file (see #995 and #1000 for more details). Everything is automated and requires no human supervision or interaction. This very release was performed this way.๐ This is quite an exciting and very necessary improvement as now any Finch maintainer (a person with a push access to a repository) can cut releases.
Other Changes
- ๐ฆ Syntax Package became obsolete (do not need to import it) as we can now derive syntax based on