Finch Versions Save

Scala combinator library for building Finagle HTTP services

v0.34.0

1 year ago

With this release the Cats Effect based version of Finch becomes the official one! 🥳 It means that finchx becomes finch again and you need to update your artifact names, this change will not be picked up automatically by Scala Steward!

And thanks to @tpetillot's this release comes with much anticipated support for Cats Effect 3! ❤️

What's Changed

Dependency updates

New Contributors

Full Changelog: https://github.com/finagle/finch/compare/v0.33.0...v0.34.0

v0.33.0

2 years ago

v0.32.1

4 years ago

Hello 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 the finch

This release is expected to be the last one for finchx prefixed artifacts. Starting from the next update we're going to decommission the Future-based finch artifacts and replace it with polymorphic one.
Effectively, it means that no finchx artifacts will be updated and you would need to update the dependency by dropping the x 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

  • Updated all the core dependencies to their latest versions
  • Add Endpoint.coproductAll for summing a list of endpoints (#1178, kudos to @joroKr21)

v0.32.0

4 years ago

See 0.32.1

v0.31.0

4 years ago
  • Update Finagle to 19.8.0 and cats-effect to 1.4.0.
  • Bug fix: Exceptions occurred outside of F[_] context in Endpoint.mapOutput are properly handled. This was an annoying issue for those who work with ZIO. Thanks @Phill101 (Detais: https://github.com/finagle/finch/pull/1142)

v0.30.0

4 years ago

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

v0.29.0

4 years ago

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:

  • Streams are now cancellable if your effect supports it (see #1082 (thanks to @joroKr21)
  • Bugfix in how charsets are fetched from requests (see #1104)

v0.28.0

5 years ago

This release introduces new functionality to build a middleware of your HTTP service.

Kleisli composition

Instead of converting Endpoint straight into Service[Request, Response], there is now an option to compile it first into Kleisli[F[_], Request, (Trace, Either[Throwable, Response])] data type (or Endpoint.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.IO
import cats.effect.IO

finch@ import cats.data.Kleisli
import cats.data.Kleisli

finch@ 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 have Sync or Async type classes available to build endpoints. It enables the use of things like StateT, Kleisli, and WriterT 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

5 years ago

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) or Stream (fs2).

scala> import fs2.Stream, io.finch._, io.finch.catsEffect._, io.finch.fs2._

scala> val bin = binaryBodyStream[Stream] // raw byte-array stream
bin: Endpoint[IO, fs2.Stream[IO, Array[Byte]]] = binaryBodyStream

scala> val str = stringBodyStream[Stream] // stream of strings
str: Endpoint[IO, fs2.Stream[IO, String]] = stringBodyStream

Similarly, accepting a stream of JSON object is possible via bodyStream or jsonBodyStream 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 Foo

scala> 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) or Enumerator 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 Foo

scala> 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.IO

val 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.IO
import 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 with io.finch.fs2._.

Dependency Updates

  • Finagle 19.1 (#1065)
  • Circe 0.11 (#1060)
  • Cats 1.5 (#1046) and Cats Effect 1.1 (#1047)

v0.26.1

5 years ago

🐞Bugfix release:

  • Endpoint.rescue was incorretly throwing MatchError 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 only finchx- modules. #1048