feat(client): return response body in deserialization errors - #78
feat(client): return response body in deserialization errors#78cbeck88 wants to merge 3 commits into
Conversation
|
Another idea could be to just use |
yeah, that's a good idea too, and it's less noise in the API. happy to rewrite the PR that way |
That'd be my preference but not sure what others think :) |
|
done, lmk what you think |
d155346 to
fbf5e34
Compare
|
rebased on master and resolved conflicts |
|
CI failure looks unrelated: 0s |
9e8e665 to
57af0ed
Compare
extremeandy
left a comment
There was a problem hiding this comment.
Thanks for this, the helper is the right extraction and the debugging motivation is clear. A few things before merging:
Blockers
-
Panic on truncation.
&body[..2000]inclient/src/lib.rsslices aStringat a byte index. If byte 2000 falls inside a multi-byte UTF-8 character this panics, so the error-reporting path can crash the caller. Usebody.floor_char_boundary(2000)or collectbody.chars().take(2000). -
Branch is behind master.
client/src/routes/vault.rson master has fourres.json().await.map_err(Into::into)calls (lines 28, 62, 72, 85) that this PR doesn't cover, so the pattern lands inconsistently. Merge is clean, so it would slip through silently. Please rebase and sweep.
Suggestions
-
Put the body in the error, not only the log. The PR description says "the errors include more detail of what didn't deserialize", but the returned value is a bare
Error::SerdeJsonwith no body. The body only appears in atracing::error!event, which library consumers without a subscriber never see. The repo already has a precedent for attaching the response body to the error value:process_responsebuildsError::BpxApiError { status_code, message }from the failed body. A sibling variant would keep the two failure paths symmetric and satisfy the stated goal:/// Response body could not be deserialized into the expected type. #[error("Failed to deserialize API response: {source}")] Deserialize { #[source] source: serde_json::Error, body: Box<str>, },
The tracing call can stay alongside it if you want the log too, though
debug!orwarn!is more typical for a library on a path that already returnsErr. -
Visibility.
json_with_contextispubwhile its siblingprocess_responseis private. Nothing outside the crate needs it, and once public it's a semver commitment.pub(crate)seems right. -
Changelog note for the variant shift. Decode failures previously surfaced as
Error::Reqwest(withis_decode()true) and now surface asError::SerdeJson. Not a compile-time break, and arguably an improvement since the serde error carries line and column, but any downstreammatchon the old variant stops matching for this case. Worth a line in CHANGELOG.md. If you go with (3), the note applies to the new variant instead. -
Drop the
Blockchain::Stablechange. It isn't mentioned in the PR and is already on master, so it's a no-op after merge but doesn't belong in this commit. -
Naming, minor.
json_with_contextnever returns context to the caller, only logs it. If you adopt (3) the name becomes accurate; otherwise something likedeserialize_json_logging_bodysays what it does.
fmt and lib clippy pass on the branch. The --all-targets clippy failure is in client/tests/integration-tests.rs, which this PR doesn't touch and which already fails at the base.
|
@cbeck88 I pushed two commits to this branch to address the review above so it can move along:
Feel free to drop both commits and do it your own way if you'd prefer. Thanks for the PR. |
Follow-ups to the review of backpack-exchange#78: - Add `Error::Deserialize { source, body }` so the response body travels with the error instead of only being logged. `Display` shows a preview truncated on a char boundary; the full body is available on the variant. - Fix the byte-index slice in the body preview, which panicked when byte 2000 fell inside a multi-byte UTF-8 character. Add unit tests. - Make the helper `pub(crate)` and rename it to `deserialize_json`. - Sweep the call sites added on master since the branch was cut (vault.rs, order.rs, markets.rs) so every route uses the helper. - Drop the duplicate `Blockchain::Stable` variant that the merge with master produced. - Lower the helper's log to `debug!` now that the error carries the body. Note for consumers: JSON decode failures are now returned as `Error::Deserialize` rather than `Error::Reqwest` (decode kind). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
@cbeck88 CI is green but the merge is blocked because Two ways forward, your pick:
Happy either way, just let me know. |
|
I'll try to sign it, thank you |
this helps to debug when the API breaks, and helped me figure out what was wrong when Monad was added
Follow-ups to the review of backpack-exchange#78: - Add `Error::Deserialize { source, body }` so the response body travels with the error instead of only being logged. `Display` shows a preview truncated on a char boundary; the full body is available on the variant. - Fix the byte-index slice in the body preview, which panicked when byte 2000 fell inside a multi-byte UTF-8 character. Add unit tests. - Make the helper `pub(crate)` and rename it to `deserialize_json`. - Sweep the call sites added on master since the branch was cut (vault.rs, order.rs, markets.rs) so every route uses the helper. - Drop the duplicate `Blockchain::Stable` variant that the merge with master produced. - Lower the helper's log to `debug!` now that the error carries the body. Note for consumers: JSON decode failures are now returned as `Error::Deserialize` rather than `Error::Reqwest` (decode kind). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
f3c5c91 to
05ae4e5
Compare
this adds a new pattern for handling errors when json bodies don't match the rust schema, so that the errors include more detail of what didn't deserialize. this helped me figure out what was wrong when the get_assets endpoint failed when monad was added