-
Notifications
You must be signed in to change notification settings - Fork 16
Switch HTTPClient response handler from a closure to a protocol #158
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This source file is part of the Swift HTTP API Proposal open source project | ||
| // | ||
| // Copyright (c) 2026 Apple Inc. and the Swift HTTP API Proposal project authors | ||
| // Licensed under Apache License v2.0 | ||
| // | ||
| // See LICENSE.txt for license information | ||
| // | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| @available(macOS 26.2, iOS 26.2, watchOS 26.2, tvOS 26.2, visionOS 26.2, *) | ||
| public struct HTTPClientClosureResponseHandler<ResponseConcludingReader, Return: ~Copyable>: HTTPClientResponseHandler, ~Copyable | ||
| where | ||
| ResponseConcludingReader: ConcludingAsyncReader & ~Copyable & SendableMetatype, | ||
| ResponseConcludingReader.Underlying: ~Copyable, | ||
| ResponseConcludingReader.Underlying.ReadElement == UInt8, | ||
| ResponseConcludingReader.FinalElement == HTTPFields? | ||
| { | ||
| private let handler: (HTTPResponse, consuming ResponseConcludingReader) async throws -> Return | ||
|
|
||
| public init(handler: @escaping (HTTPResponse, consuming ResponseConcludingReader) async throws -> Return) { | ||
| self.handler = handler | ||
| } | ||
|
|
||
| public func handleInformational(response: HTTPResponse) async throws { | ||
| } | ||
|
|
||
| public func handle(response: HTTPResponse, responseBodyAndTrailers: consuming ResponseConcludingReader) async throws -> Return { | ||
| try await self.handler(response, responseBodyAndTrailers) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This source file is part of the Swift HTTP API Proposal open source project | ||
| // | ||
| // Copyright (c) 2026 Apple Inc. and the Swift HTTP API Proposal project authors | ||
| // Licensed under Apache License v2.0 | ||
| // | ||
| // See LICENSE.txt for license information | ||
| // | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| @available(macOS 26.2, iOS 26.2, watchOS 26.2, tvOS 26.2, visionOS 26.2, *) | ||
| public protocol HTTPClientResponseHandler: ~Copyable { | ||
| associatedtype ResponseConcludingReader: ConcludingAsyncReader, ~Copyable, SendableMetatype | ||
| where | ||
| ResponseConcludingReader.Underlying: ~Copyable, | ||
| ResponseConcludingReader.Underlying.ReadElement == UInt8, | ||
| ResponseConcludingReader.FinalElement == HTTPFields? | ||
| associatedtype Return: ~Copyable | ||
|
|
||
| func handleInformational(response: HTTPResponse) async throws | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What do we expect a user to do in here? Is this just for them to observe it? Can they take any action on an informational response?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It depends on the status code. E.g. start sending the request body after 100 continue (the backing implementation can also handle this by delaying calling the closure until 100 continue); prefetching a resource after 103 early hints. |
||
|
|
||
| func handle(response: HTTPResponse, responseBodyAndTrailers: consuming ResponseConcludingReader) async throws -> Return | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This source file is part of the Swift HTTP API Proposal open source project | ||
| // | ||
| // Copyright (c) 2026 Apple Inc. and the Swift HTTP API Proposal project authors | ||
| // Licensed under Apache License v2.0 | ||
| // | ||
| // See LICENSE.txt for license information | ||
| // | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| @available(macOS 26.2, iOS 26.2, watchOS 26.2, tvOS 26.2, visionOS 26.2, *) | ||
| package struct HTTPClientTransformedResponseHandler<OtherHandler: HTTPClientResponseHandler & ~Copyable, ResponseConcludingReader>: | ||
| HTTPClientResponseHandler, ~Copyable | ||
| where | ||
| OtherHandler.ResponseConcludingReader: ~Copyable, | ||
| OtherHandler.ResponseConcludingReader.Underlying: ~Copyable, | ||
| OtherHandler.Return: ~Copyable, | ||
| ResponseConcludingReader: ConcludingAsyncReader & ~Copyable & SendableMetatype, | ||
| ResponseConcludingReader.Underlying: ~Copyable, | ||
| ResponseConcludingReader.Underlying.ReadElement == UInt8, | ||
| ResponseConcludingReader.FinalElement == HTTPFields? | ||
| { | ||
| package typealias Return = OtherHandler.Return | ||
|
|
||
| private let other: OtherHandler | ||
| private let transform: @Sendable (consuming ResponseConcludingReader) -> OtherHandler.ResponseConcludingReader | ||
|
|
||
| package init( | ||
| other: consuming OtherHandler, | ||
| transform: @escaping @Sendable (consuming ResponseConcludingReader) -> OtherHandler.ResponseConcludingReader | ||
| ) { | ||
| self.other = other | ||
| self.transform = transform | ||
| } | ||
|
|
||
| package func handleInformational(response: HTTPResponse) async throws { | ||
| try await self.other.handleInformational(response: response) | ||
| } | ||
|
|
||
| package func handle(response: HTTPResponse, responseBodyAndTrailers: consuming ResponseConcludingReader) async throws -> Return { | ||
| try await self.other.handle(response: response, responseBodyAndTrailers: self.transform(responseBodyAndTrailers)) | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was not able to get it to work with primary associated types due to
SuppressedAssociatedTypesWithDefaultsrequiring ~Copyable forResponseHandler.ResponseConcludingReader