This release is probably the most important and big one since 0.1.0. A bunch of cool and fancy features as well as some breaking API changes are introduced here. We decided to get them all out of the way at once rather than incrementally breaking API. Although, we don't plan to make big API changes in further releases. So, this release might be treated as early pre-alpha 1.0.0.
New Features
We will start with new features. There are two of them:
- New route combinators API
- New request reader API
Route Combinators
The route combinators API is introduced in favour of io.finch.Endpoint
. While we haven't deprecated the old-style endpoint yet, it's highly recommended to consider migration to the new API. The example bellow, shows how the old-style endpoint might be rewritten using the route combinators API.
// The old-style endpoint
object Users extends Endpoint {
def route {
case Method.Get -> Root / "users" => GetAllUsers
case Method.Get -> Root / "users" / id => GetUser(id)
}
}
// The new-style endpoint
val users =
(Get / "users" /> GetAllUsers) |
(Get / "users" / int /> GetUser)
See docs on routers for more details.
Applicative Request Reader
RequestReader
s applicative behaviour introduces a new way to compose readers together. In addition to monadic API, request readers are support applicative API via operand ~
. The main advantage of using the applicative API is that it allows to collect errors rather then fail-fast. We recommend to migrate the monadic request readers to applicative request readers and respond clients the rich set of errors rather then only first one. The following example shows how monadic request reader might be rewritten in the applicative style.
// the monadic style
val monadicUser = for {
name <- RequiredParam("name")
age <- RequiredIntParam("age")
} yield User(name, age)
// the applicate style
val applicativeUser =
RequiredParam("name") ~ RequiredParam("age") map {
case name ~ age => User(name, age)
}
Reusable Validation Rules
This item goes to features but it also brakes the current API around ValidationRule
. Since version 0.5.0 validation rule is no longer an instance of RequestReader
but standalone abstraction, which might be composed with request readers. Brand new request reader API introduces a new approach of validating request items. Instead of old-style ValidationRule
the should
or shouldNot
methods should be used. The following example shows the difference between the old-style and new-style validation.
// the old-style validation
val oldNumber = for {
n <- RequiredIntParam("n")
_ <- ValidationRule("n", "should be greater than 0") { n > 0 }
_ <- ValidationRule("n", "should be less than 100") { n < 100 }
} yield n
// the new-style inline validation
val newNumber =
RequiredIntParam("n") should("be greater than 0") { _ > 0 } should("be less than 100") { _ < 100 }
The most beauty thing about new validation is that reusable ValidationRule
s might dramatically simplify the example above. Keeping in mind that validation rules are composable and there are built-in rules beGreaterThan
and beLessThan
, the example might be rewritten as shown bellow.
val newNumber = RequiredIntParam("n") should (beGreaterThan(0) and beLessThan(100))
See docs on request validation.
as[A]
method as a replacement for typed readers
This release also introduces new style of defining typed readers, i.e., RequiredIntParam
, OptionalFloatParam
, etc. It's recommended to use new as[A]
API instead. The following example shows the difference.
// old-style typed reader
val a = RequredIntParam("a")
// new-style typed reader
val b = RequiredParam("a").as[Int]
Breaking API Changes
Request Reader Errors
The whole exceptions hierarchy was revised. We ended up having just three base exceptions thrown by RequestReader
: NotPresent
, NotParsed
and NotValid
. The following example shows a pattern according to which exception handling should be changed.
// the old-style handling
x handle {
case ParamNotFound(param) => ???
}
// the new style-handling
y handle {
case NotPresent(ParamItem(param)) => ???
}
Renamed Things
The only thing we renamed in this release is body readers. In the following list X
means either Required
or Optional
.
XStringBody
renamed toXBody
XArrayBody
renamed toXBinaryBody
Downloads
Grad the new release at Maven Central:
libraryDependencies ++= Seq(
"com.github.finagle" %% "[finch-module]" % "0.5.0"
)
Thanks to awesome contributors @jenshalm, @rpless, @travisbrown who made this release possible!