Skip to content

Finch 0.28

Compare
Choose a tag to compare
@sergeykolbasov sergeykolbasov released this 27 Feb 23:53
· 567 commits to master since this release

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.