Uses covariant overrides so that those collecting Feign configuration
via `Feign.Builder` can cast into `HystrixFeign.builder` to target an
api.
Closes#313
Before this change, if someone accidentally left out the HTTP method in
a `@RequestLine` annotation, they'd get an undecipherable error like:
"Body parameters cannot be used with form parameters." from Contract.java.
This makes the omission easier to find by changing the message to:
"RequestLine annotation didn't start with an HTTP verb..."
Fixes#310
Fallbacks are known values, which you return when there's an error invoking an http method.
For example, you can return a cached result as opposed to raising an error to the caller. To use
this feature, pass a safe implementation of your target interface as the last parameter to `HystrixFeign.Builder.target`.
Here's an example:
```java
// When dealing with fallbacks, it is less tedious to keep interfaces small.
interface GitHub {
@RequestLine("GET /repos/{owner}/{repo}/contributors")
List<String> contributors(@Param("owner") String owner, @Param("repo") String repo);
}
// This instance will be invoked if there are errors of any kind.
GitHub fallback = (owner, repo) -> {
if (owner.equals("Netflix") && repo.equals("feign")) {
return Arrays.asList("stuarthendren"); // inspired this approach!
} else {
return Collections.emptyList();
}
};
GitHub github = HystrixFeign.builder()
...
.target(GitHub.class, "https://api.github.com", fallback);
```
Credit to the idea goes to @stuarthendren!
Removing exception wrapping adds flexibility to the interplay of Decoder and ErrorDecoder:
A Decoder can now delegate to an ErrorDecoder and the original ErrorDecoder exception gets
thrown rather than a Feign-specific DecodeException. An example use-case is a Jackson/Gson
implementation of special 404-handling of Optional<Foo> methods: when the Feign client has
decode404() enabled, then the Decoder is in charge of dispatching 404 to Optional#absent
where applicable, or to a delegate ErrorDecoder otherwise; consistent exception handling
requires that the exception produced by the ErrorDecoder does not wrapped.
This adds the `Feign.Builder.decode404()` flag which indicates decoders
should process responses with 404 status. It also changes all
first-party decoders (like gson) to return well-known empty values by
default. Further customization is possible by wrapping or creating a
custom decoder.
Prior to this change, we used custom invocation handlers as the way to
add fallback values based on exception or return status. `feign-hystrix`
uses this to return `HystrixCommand<X>`, but the general pattern applies
to anything that has a type representing both success and failure, such
as `Try<X>` or `Observable<X>`.
As we define it here, 404 status is not a retry or fallback policy, it
is just empty semantics. By limiting Feign's special processing to 404,
we gain a lot with very little supporting code.
If instead we opened all codes, Feign could easily turn bad request,
redirect, or server errors silently to null. This sort of configuration
issue is hard to troubleshoot. 404 -> empty is a very safe policy vs
all codes.
Moreover, we don't create a cliff, where folks seeking fallback policy
eventually realize they can't if only given a response code. Fallback
systems like Hystrix address exceptions that occur before or in lieu of
a response. By special-casing 404, we avoid a slippery slope of half-
implementing Hystrix.
Finally, 404 handling has been commonly requested: it has a clear use-
case, and through that value. This design supports that without breaking
compatibility, or impacting existing integrations such as Hystrix or
Ribbon.
See #238#287