Fix HTTPDataResponse.success error handling and converge failure reporting - #34
Merged
Conversation
Both success overloads wrapped the status check and the result decode in one do, so a 2xx whose body failed to decode as R was re-decoded as E - returning a bogus .error for a successful response, or masking the real DecodingError. Status now selects the branch and decode failures propagate. A failure whose body does not decode as E throws HTTPResponseError.unsuccessful rather than a bare DecodingError, keeping the status and raw bytes. Adds code and bodyString accessors so callers can read either case without matching both. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
🦋 Changeset detectedLatest commit: 60f06df The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
expectSuccess() reported .unsuccessfulString whenever the body happened to be UTF-8, while expect(statusCode:) and the new decodedError reported .unsuccessful for the same response - so two near-identically named methods disagreed, and an empty body arrived as .unsuccessfulString(code, "") since String(data: Data()) is "" rather than nil. .unsuccessfulString stays in the enum so existing callers compile; it is just no longer thrown from here. bodyString reads either case. Also covers success(code:) against a real failure status, a bodiless 2xx, and corrects a test comment that implied it pinned the fix when it passes against the old implementation too. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Merged
ThisIsMissEm
left a comment
Contributor
There was a problem hiding this comment.
I think this makes sense to me
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Both
successoverloads wrapped the status check and the result decode in onedo, so a decode failure on a 2xx fell into thecatchand got re-decoded as the error type. Status now selects the branch and decode failures propagate.Behavior changes
Three, all visible to oauth4swift — the only consumer.
.error(ErrorResponse, 200), soprocessGenericAccessTokenreported a malformed token response asErrors.invalidRequest— an OAuth protocol error for what is really a decode failure. Now: throws the realDecodingErrorfor the result type.DecodingError, status and bytes lost. Now:HTTPResponseError.unsuccessful(code, data)..unsuccessful.expectSuccess()alone reported.unsuccessfulStringwhenever the body happened to be UTF-8, so two near-identically-named methods disagreed for the same response — and an empty body arrived as.unsuccessfulString(code, ""), sinceString(data: Data(), encoding: .utf8)is""rather thannil..unsuccessfulStringstays in the enum so existing callers compile; it is simply no longer thrown from this module.HTTPResponseErrorgainscodeandbodyString, which read either case — that is the migration path for anyone who was matching.unsuccessfulString. Nothing in oauth4swift, AtprotoOAuth, AtprotoClient or germDM catches anHTTPResponseErrorthrown by anHTTPDataResponsemethod today; the three sites that name.unsuccessfulStringuse the type as a carrier for their own throws.Note
codecan carry a 2xx:expect(statusCode: 201)on a 200 reports.unsuccessful(200, …). That is longstanding behavior ofexpect(statusCode:), andsuccess(code:)now matches it rather than diverging — worth knowing before branching oncode.Tests
First coverage this type has had. I established which tests are genuine regression tests by reverting only the two
successbodies while keeping every addition: three fail, and they are marked as such in the file. The rest pin existing behavior and say so, including one whose comment previously implied otherwise.That distinction depends on a fixture that decodes as the error type but not the result type — a naive
"not json"body throwsDecodingErrorunder both implementations and proves nothing.Also covered:
success(code:)against a real failure status, a bodiless 2xx (documents a sharp edge rather than endorsing it —successalways has a result type to decode, so callers with no success body want #35'sexpectSuccess(orError:)), and agreement across all three failure paths.Test notes
swift testgreen. Also ran oauth4swift against this branch viaswift package edit: it compiles, its suite passes, and a throwaway harness overprocessPushedAuthorizationResponse,processGenericAccessTokenand both discovery call sites confirmed the unchanged paths still behave and the changed ones improve. oauth4swift has no tests of its own over those paths, and this reaches AtprotoOAuth by transitive resolution as soon as it releases — that harness was the only gate, so it is worth a standing test in oauth4swift eventually.🤖 Generated with Claude Code