Highlights
- New package
jackson
- a Jackson support - New method
ResponseBuilder.withCookies()
- Updated
demo
with custom request type and implicit conversion:Seq[ToJson] => ToJson
- Scaladoc
Finch becomes more general! Three major components of Finch were generalised in this release:
Endpoint
is no longer depend onHttpRequest
: anyReq
type may be used insteadResponseBuilder
is no longer depend on JSON response type: any media type may be built with itRequestReader
is no longer depend on JSON: any typeA
may be read withRequiredBody[A]
andOptionalBody[A]
Implicit view Req => HttpRequest
instead sub-typing
Finch moved forward to composition from inheritance. Since, 0.4.0 release, an Endpoint
changed its type-parameters bound from Endpoint[Req <: HttpRequest]
to Endpoint[Req, Rep]
. Thus, in fact, any request type may be used in the endpoint, even the custom case class like
// we compose MyRequest with HttpRequest but not extend it
case class MyRequest(http: HttpRequest)
val e: Endpoint[MyRequest, HttpResponse]
There is also an implicit conversion in io.finch._
that converts Endpoint[Req, Rep]
to Finagle Service[Req, Rep]
. Thus, the method Endpoint.toService
is no longer exist. In order to enable the implicit conversion there is should be an implicit view Req => HttpRequest
available in the scope. For example for MyRequest
it looks like:
implicit val myReqEv = (req: MyRequest) => req.http
Having an implicit view imported in the scope, an Endpoint
may be treated as a usual Finagle Service
:
case class MyRequest(http: HttpRequest)
implicit val myReqEv = (req: MyRequest) => req.http
val e: Endpoint[MyRequest, HttpResponse]
// an endpoint `e` will be converted to service implicitly
Httpx.serve(new InetSocketAddress(8081), e)
Note, that in case of using pure HttpRequest
and HttpEndpoint
there is no need to define an implicit view from HttpRequest => HttpRequest
since it's already defined in Scala's Predef.
This new functionality is also supported by RequestReader
, which previously had a signature:
trait RequestReader[A] {
def apply(req: HttpRequest): Future[A]
}
Since release 0.4.0 RequestReader
takes any request type, which has an implicit view to HttpRequest
. In fact, signature has been changed to:
trait RequestReader[A] {
def apply[Req](req: Req)(implicit ev: Req => HttpRequest): Future[A]
}
This allows to use requests readers smoothly even with custom request types like MyRequest
:
case class MyRequest(http: HttpRequest)
implicit val myReqEv = (req: MyRequest) => req.http
val req: MyRequest = ???
// we don't need to call it as `req.http` since there is an implicit view available
val s: Future[String] = RequiredParam("name")(req)
Finch provides the developers all the suitable abstractions to switch from inheritance to composition. While it's still possible to extends HttpRequest
and pass it around, the composition in form MyRequest(http: HttpRequest)
is preferred.
Generalized EncodeResponse
/DecodeRequest
instead of EncodeJson
/DecodeJson
Finch moved away from JSON dependency to general concept of some type A
that might be decoded from request using the DecodeRequest
and encoded to response using the EncodeResoponse
. This gives the opportunity to support not just JSON but any format (i.e., XML, EDN or even custom case class). Unless it looks like a big change, the JSON support via pluggable libraries remanned the same with type changes in API:
RequiredBody
/OptionalBody
renamed toRequiredArrayBody
/OptionalArrayBody
RequiredJsonBody
/OptionalJsonBody
renamed toRequiredBody
/OptionalBody
Thus the usage of new API with finch-json
looks like:
val readJson: RequestReader[Json] = RequiredBody[Json]
The following example demonstrates the power of new concept by defining a custom decoder for Double
values. Thus the double values encoded in request body may be read with predefined reader RequiredBody
.
implicit val decodeDouble = new DecodeRequest[Double] {
def apply(s: String): Option[Double] =
try { Some(s.toDouble) } catch { case _: NumberFormatException => None }
}
val req: HttpRequest = ???
val readDouble: RequestReader[Double] = RequiredBody[Double]
val double = readDouble(req)
Grab on Maven Central:
libraryDependencies ++= Seq(
"com.github.finagle" %% "[finch-module]" % "0.4.0"
)
As always kudos to awesome contributors: @pasviegas, @rodrigopr, @rpless, @travisbrown!