refactor: unify the HTTP exception hierarchy and route errors through the factory#100
Conversation
… Retryable interface The response-carrying exception hierarchy had two overlapping bases and the factory that produces the typed family was never wired into the error path. - Collapse `HttpResponseException` (an `IOException` carrying a `Response` + optional error value) into `HttpException`. `HttpException` becomes the single response-carrying base; it gains an optional `value` slot for a deserialized error payload so the generated layer can stamp a typed body later. Transport failures keep using the `NetworkException` (`IOException`) sibling, so existing `catch (IOException)` sites for transport errors are unaffected. - Introduce a `Retryable` interface (`val isRetryable: Boolean`) and implement it on both `HttpException` and `NetworkException`. The two types previously disagreed on the accessor name (`retryable` vs `isRetryable`); they now expose the same member through the interface. Retry classification in `RetryStep` keys off `Retryable` instead of matching concrete types, so a new retryable exception type participates automatically. The set of retryable statuses is unchanged (408/429 and 5xx except 501/505, still derived from `RetryUtils`). - Wire `HttpExceptionFactory.fromResponse` into the live error path via a new `ThrowOnHttpErrorStep` response step: on a 4xx/5xx response it throws the factory's typed exception, which `ResponsePipeline` turns into a failure outcome that flows through the recovery chain (including retry) like a transport failure. Previously the factory had no callers and 4xx/5xx responses never produced the typed subclass family. This is a binary-incompatible change to the public exception API: the `HttpResponseException` type is removed, the `retryable` getter on `HttpException` and `NetworkException` is renamed to `isRetryable`, and `HttpException` gains a `value` property and a corresponding constructor parameter. API snapshot regenerated; docs updated.
Review notesThis unifies the response-carrying exception story: it removes Major
Minor
Nits
Questions
Praise
|
ThrowOnHttpErrorStep built the exception from the live response, but the pipeline closes that response (and its body) as soon as the step throws, so the error body was unreadable on the resulting Failure — contradicting the bodySnapshot and stream-on-demand contract. Buffer the error body into a bounded, replayable in-memory body before constructing the exception, capped at HttpException.DEFAULT_SNAPSHOT_BYTES so a large 5xx body cannot exhaust memory. Add a test that the failure's body and bodySnapshot are still readable after the pipeline closes the original. Forward the value slot through the concrete HttpException subclasses so a codegen subclass derived from a concrete type (as the base KDoc describes) can stamp a typed payload; previously only the abstract base accepted it. Single-source the 400..599 error boundary by adding isErrorStatus and fromResponseOrNull to HttpExceptionFactory and having the step use them, instead of redeclaring the range. Tighten the value round-trip test to assertSame, reword a test comment off tracker IDs, and soften the docs so they describe ThrowOnHttpErrorStep as a building block rather than implying a default pipeline wires it. Regenerate the API snapshot.
…ng-unification # Conflicts: # README.md
The buffered error body is capped at DEFAULT_SNAPSHOT_BYTES; an oversized body is hard-truncated with no marker. Document that downstream consumers deserializing the buffered body must tolerate a structurally incomplete payload, and that callers needing the full body must read it before this step runs.
Summary
Two related error-handling changes.
Unify the exception hierarchy (#37 — breaking)
HttpResponseException(anIOExceptioncarrying aResponse) duplicatedHttpException's role and had no production callers. It is removed;HttpExceptionbecomes the single response-carrying type and gains an optionalvalueslot for a parsed error body. A smallRetryableinterface (isRetryable) is hoisted and implemented by bothHttpExceptionandNetworkException, so retry classification keys off the interface rather than matching concrete types (the two types previously exposed the flag under different names). This is a binary-incompatible change, appropriate at0.0.1-alpha.Route the error path through the factory (#23)
HttpExceptionFactory.fromResponse(...)existed but had no callers. A newThrowOnHttpErrorStep(a response-pipeline step) turns a 4xx/5xx response into the factory's exception; because that exception isRetryable, it flows through the recovery chain and retry classification uniformly.The retryable status set is unchanged. New tests cover the wired error path, the collapsed exception carrying what the removed type used to, and
Retryable-driven retry classification. The API snapshot is regenerated.Closes #23
Closes #37