Skip to content

Commit 110ab5e

Browse files
committed
HTTPClientRequest & HTTPClientResponse
1 parent f96567c commit 110ab5e

File tree

1 file changed

+24
-18
lines changed

1 file changed

+24
-18
lines changed

docs/async-await.md

+24-18
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ This proposal describes what these APIs could look like and explores some of the
1212

1313
## Proposed API additions
1414

15-
### New `AsyncRequest` type
15+
### New `HTTPClientRequest` type
1616

17-
The proposed new `AsyncRequest` shall be a simple swift structure.
17+
The proposed new `HTTPClientRequest` shall be a simple swift structure.
1818

1919
```swift
20-
struct AsyncRequest {
20+
struct HTTPClientRequest {
2121
/// The requests url.
2222
var url: String
2323

@@ -39,7 +39,7 @@ struct AsyncRequest {
3939
}
4040
```
4141

42-
A notable change from the current [`HTTPRequest`][HTTPRequest] is that the url is not of type `URL`. This makes the creation of a request non throwing. Existing issues regarding current API:
42+
A notable change from the current [`HTTPClient.Request`][HTTPClient.Request] is that the url is not of type `URL`. This makes the creation of a request non throwing. Existing issues regarding current API:
4343

4444
- [HTTPClient.Request.url is a let constant][issue-395]
4545
- [refactor to make request non-throwing](https://github.com/swift-server/async-http-client/pull/56)
@@ -51,18 +51,18 @@ In normal try/catch flows this should not change the control flow:
5151

5252
```swift
5353
do {
54-
var request = AsyncRequest(url: "invalidurl")
54+
var request = HTTPClientRequest(url: "invalidurl")
5555
try await httpClient.execute(request, deadline: .now() + .seconds(3))
5656
} catch {
5757
print(error)
5858
}
5959
```
6060

61-
If the library code throws from the AsyncRequest creation or the request invocation the user will, in normal use cases, handle the error in the same catch block.
61+
If the library code throws from the `HTTPClientRequest` creation or the request invocation the user will, in normal use cases, handle the error in the same catch block.
6262

63-
#### Body streaming
63+
#### Request body streaming
6464

65-
The new AsyncRequest has a new body type, that is wrapper around an internal enum. This allows us to evolve this type for use-cases that we are not aware of today.
65+
The new `HTTPClientRequest` has a new body type, that is wrapper around an internal enum. This allows us to evolve this type for use-cases that we are not aware of today.
6666

6767
```swift
6868
public struct Body {
@@ -74,16 +74,16 @@ public struct Body {
7474
}
7575
```
7676

77-
The main difference to today's `Request.Body` type is the lack of a `StreamWriter` for streaming scenarios. The existing StreamWriter offered the user an API to write into (thus the user was in control of when writing happened). The new `AsyncRequest.Body` uses `AsyncSequence`s to stream requests. By iterating over the provided AsyncSequence, the HTTPClient is in control when writes happen, and can ask for more data efficiently.
77+
The main difference to today's `Request.Body` type is the lack of a `StreamWriter` for streaming scenarios. The existing StreamWriter offered the user an API to write into (thus the user was in control of when writing happened). The new `HTTPClientRequest.Body` uses `AsyncSequence`s to stream requests. By iterating over the provided AsyncSequence, the HTTPClient is in control when writes happen, and can ask for more data efficiently.
7878

7979
Using the `AsyncSequence` from the Swift standard library as our upload stream mechanism dramatically reduces the learning curve for new users.
8080

81-
### New `AsyncResponse` type
81+
### New `HTTPClientResponse` type
8282

83-
The `AsyncResponse` looks more similar to the existing `Response` type. The biggest difference is again the `body` property, which is now an `AsyncSequence` of `ByteBuffer`s instead of a single optional `ByteBuffer?`. This will make every response on AsyncHTTPClient streaming by default.
83+
The `HTTPClientResponse` looks more similar to the existing [`HTTPClient.Response`][HTTPClient.Response] type. The biggest difference is again the `body` property, which is now an `AsyncSequence` of `ByteBuffer`s instead of a single optional `ByteBuffer?`. This will make every response on AsyncHTTPClient streaming by default. As with `HTTPClientRequest`, we dropped the namespacing on `HTTPClient` to allow easier discovery with autocompletion.
8484

8585
```swift
86-
public struct AsyncResponse {
86+
public struct HTTPClientResponse {
8787
/// the used http version
8888
public var version: HTTPVersion
8989
/// the http response status
@@ -94,7 +94,7 @@ public struct AsyncResponse {
9494
public var body: Body
9595
}
9696

97-
extension AsyncResponse {
97+
extension HTTPClientResponse {
9898
public struct Body: AsyncSequence {
9999
public typealias Element = ByteBuffer
100100
public typealias AsyncIterator = Iterator
@@ -110,7 +110,11 @@ extension AsyncResponse {
110110
}
111111
```
112112

113-
At a later point we could add trailers to the AsyncResponse as effectful properties.
113+
Note: The user must consume the `Body` stream or drop the `HTTPClientResponse`, to ensure that the
114+
internal HTTPClient connection can move forward. Dropping the `HTTPClientResponse` would lead to a
115+
request cancellation which in turn would lead to a close of an exisiting HTTP/1.1 connection.
116+
117+
At a later point we could add trailers to the `HTTPClientResponse` as effectful properties:
114118

115119
```swift
116120
public var trailers: HTTPHeaders? { async throws }
@@ -120,23 +124,24 @@ However we will need to make sure that the user has consumed the body stream com
120124

121125
```swift
122126
do {
123-
var request = AsyncRequest(url: "https://swift.org/")
127+
var request = HTTPClientRequest(url: "https://swift.org/")
124128
let response = try await httpClient.execute(request, deadline: .now() + .seconds(3))
125129

126130
var trailers = try await response.trailers // can not move forward since body must be consumed before.
127131
} catch {
128132
print(error)
129133
}
130-
131134
```
132135

136+
In such a case we can either throw an error or crash.
137+
133138
### New invocation
134139

135140
The new way to invoke a request shall look like this:
136141

137142
```swift
138143
extension HTTPClient {
139-
func execute(_ request: AsyncRequest, deadline: NIODeadline) async throws -> AsyncResponse
144+
func execute(_ request: HTTPClientRequest, deadline: NIODeadline) async throws -> HTTPClientResponse
140145
}
141146
```
142147

@@ -165,4 +170,5 @@ extension HTTPClient {
165170
[issue-392]: https://github.com/swift-server/async-http-client/issues/392
166171
[issue-395]: https://github.com/swift-server/async-http-client/issues/395
167172

168-
[HTTPRequest]: https://github.com/swift-server/async-http-client/blob/main/Sources/AsyncHTTPClient/HTTPHandler.swift#L96-L318
173+
[HTTPClient.Request]: https://github.com/swift-server/async-http-client/blob/main/Sources/AsyncHTTPClient/HTTPHandler.swift#L96-L318
174+
[HTTPClient.Response]: https://github.com/swift-server/async-http-client/blob/main/Sources/AsyncHTTPClient/HTTPHandler.swift#L320-L364

0 commit comments

Comments
 (0)